summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne Juul <arnej@verizonmedia.com>2020-08-13 09:48:16 +0000
committerArne Juul <arnej@verizonmedia.com>2020-08-16 09:47:05 +0000
commit7dfff82ef775341d2784b7b91092f78553748333 (patch)
tree601cc6e5defd919d0122c20f00b3c943ae540bd8
parente98b5a77300eda52f082b9c17b9cf4915b3fe4b0 (diff)
add JSON (lite) format for geo locations
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.cpp86
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.h4
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.cpp36
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.h1
4 files changed, 122 insertions, 5 deletions
diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
index 05c53348699..935e3e300eb 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
+++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
@@ -3,6 +3,11 @@
#include "geo_location_parser.h"
#include <limits>
#include <vespa/vespalib/stllike/asciistream.h>
+#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/data/slime/json_format.h>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".searchlib.common.geo_location_parser");
namespace {
@@ -39,7 +44,7 @@ GeoLocationParser::GeoLocationParser()
_max_x(std::numeric_limits<int32_t>::max()),
_min_y(std::numeric_limits<int32_t>::min()),
_max_y(std::numeric_limits<int32_t>::max()),
- _parseError(NULL)
+ _parseError(nullptr)
{}
bool
@@ -62,7 +67,7 @@ GeoLocationParser::parseOldFormatWithField(const std::string &str)
{
auto sep = str.find(':');
if (sep == std::string::npos) {
- _parseError = "Location string lacks field specification.";
+ _parseError = "Location string lacks field specification";
return false;
}
_field_name = str.substr(0, sep);
@@ -179,9 +184,86 @@ GeoLocationParser::parseOldFormat(const std::string &locStr)
return _valid;
}
+bool
+GeoLocationParser::parseWithField(const std::string &str)
+{
+ auto sep = str.find(':');
+ if (sep == std::string::npos) {
+ _parseError = "Location string lacks field specification";
+ return false;
+ }
+ _field_name = str.substr(0, sep);
+ std::string only_loc = str.substr(sep + 1);
+ return parseNoField(only_loc);
+}
+
+bool
+GeoLocationParser::parseNoField(const std::string &str)
+{
+ if (str.empty()) {
+ _parseError = "Location string is empty";
+ return false;
+ }
+ if (str[0] == '(' || str[0] == '[') {
+ return parseOldFormat(str);
+ }
+ if (str[0] != '{') {
+ _parseError = "Location string should start with '{'";
+ return false;
+ }
+ return parseJsonFormat(str);
+}
+
+bool
+GeoLocationParser::parseJsonFormat(const std::string &str)
+{
+ vespalib::Slime slime;
+ size_t decoded = vespalib::slime::JsonFormat::decode(str, slime);
+ if (decoded == 0) {
+ LOG(warning, "bad location JSON: %s\n",
+ slime.get()["error_message"].asString().data);
+ _parseError = "Failed decoding JSON format location";
+ return false;
+ }
+ // fprintf(stderr, "parsed location JSON %s -> %s\n", str.c_str(), slime.toString().c_str());
+ const auto &root = slime.get();
+ const auto &point = root["p"];
+ const auto &radius = root["r"];
+ const auto &aspect = root["a"];
+ const auto &bbox = root["b"];
+
+ if (point.valid()) {
+ _x = point["x"].asLong();
+ _y = point["y"].asLong();
+ _has_point = true;
+ }
+ if (radius.valid()) {
+ _radius = radius.asLong();
+ }
+ if (aspect.valid()) {
+ _x_aspect = aspect.asLong();
+ }
+ if (bbox.valid()) {
+ _min_x = bbox["x"][0].asLong();
+ _max_x = bbox["x"][1].asLong();
+ _min_y = bbox["y"][0].asLong();
+ _max_y = bbox["y"][1].asLong();
+ _has_bounding_box = true;
+ }
+ if (_has_point || _has_bounding_box) {
+ _valid = true;
+ } else {
+ _parseError = "Neither point nor bounding box found";
+ }
+ return _valid;
+}
+
GeoLocation
GeoLocationParser::getGeoLocation() const
{
+ if (! _valid) {
+ return GeoLocation();
+ }
GeoLocation::Aspect aspect(_x_aspect);
if (_has_bounding_box) {
GeoLocation::Range x_range{_min_x, _max_x};
diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.h b/searchlib/src/vespa/searchlib/common/geo_location_parser.h
index 8936a620d21..7d725f4a035 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location_parser.h
+++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.h
@@ -17,6 +17,9 @@ class GeoLocationParser
public:
GeoLocationParser();
+ bool parseNoField(const std::string &locStr);
+ bool parseWithField(const std::string &locStr);
+
bool parseOldFormat(const std::string &locStr);
bool parseOldFormatWithField(const std::string &str);
@@ -42,6 +45,7 @@ private:
const char *_parseError;
bool correctDimensionalitySkip(const char * &p);
+ bool parseJsonFormat(const std::string &locStr);
};
} // namespace
diff --git a/searchlib/src/vespa/searchlib/query/tree/location.cpp b/searchlib/src/vespa/searchlib/query/tree/location.cpp
index 6e678f9e682..44f0b82d304 100644
--- a/searchlib/src/vespa/searchlib/query/tree/location.cpp
+++ b/searchlib/src/vespa/searchlib/query/tree/location.cpp
@@ -33,12 +33,13 @@ Location::Location(const Rectangle &rect)
bool
Location::operator==(const Location &other) const
{
- auto me = getOldFormatString();
- auto it = other.getOldFormatString();
+ auto me = getJsonFormatString();
+ auto it = other.getJsonFormatString();
if (me == it) {
return true;
} else {
// dump 'me' and 'it' here if unit tests fail
+ // fprintf(stderr, "me='%s', it='%s'\n", me.c_str(), it.c_str());
return false;
}
}
@@ -69,8 +70,37 @@ Location::getOldFormatString() const
return buf.str();
}
+std::string
+Location::getJsonFormatString() const
+{
+ // Only produce what search::common::GeoLocationParser can parse
+ vespalib::asciistream buf;
+ buf << "{";
+ if (has_point) {
+ buf << "p:{x:" << point.x << ",y:" << point.y << "}";
+ if (has_radius()) {
+ buf << "," << "r:" << radius;
+ }
+ if (x_aspect.active()) {
+ buf << "," << "a:" << x_aspect.multiplier;
+ }
+ }
+ if (bounding_box.active()) {
+ if (has_point) {
+ buf << ",";
+ }
+ buf << "b:{x:[" << bounding_box.x.low
+ << "," << bounding_box.x.high
+ << "],y:[" << bounding_box.y.low
+ << "," << bounding_box.y.high
+ << "]}" ;
+ }
+ buf << "}";
+ return buf.str();
+}
+
vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc) {
return out << loc.getOldFormatString();
}
-}
+} // namespace
diff --git a/searchlib/src/vespa/searchlib/query/tree/location.h b/searchlib/src/vespa/searchlib/query/tree/location.h
index 6b8090f45e1..143282e2958 100644
--- a/searchlib/src/vespa/searchlib/query/tree/location.h
+++ b/searchlib/src/vespa/searchlib/query/tree/location.h
@@ -22,6 +22,7 @@ public:
bool operator==(const Location &other) const;
std::string getOldFormatString() const;
+ std::string getJsonFormatString() const;
};
vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc);