diff options
author | Arne Juul <arnej@verizonmedia.com> | 2020-08-13 09:48:16 +0000 |
---|---|---|
committer | Arne Juul <arnej@verizonmedia.com> | 2020-08-16 09:47:05 +0000 |
commit | 7dfff82ef775341d2784b7b91092f78553748333 (patch) | |
tree | 601cc6e5defd919d0122c20f00b3c943ae540bd8 | |
parent | e98b5a77300eda52f082b9c17b9cf4915b3fe4b0 (diff) |
add JSON (lite) format for geo locations
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); |