diff options
Diffstat (limited to 'searchlib')
36 files changed, 936 insertions, 544 deletions
diff --git a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp b/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp index a64704a08e9..cf1506a9118 100644 --- a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp +++ b/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp @@ -17,7 +17,6 @@ #include <vespa/searchlib/attribute/singlestringattribute.h> #include <vespa/searchlib/index/dummyfileheadercontext.h> #include <vespa/searchlib/query/tree/location.h> -#include <vespa/searchlib/query/tree/point.h> #include <vespa/searchlib/query/tree/simplequery.h> #include <vespa/searchlib/queryeval/document_weight_search_iterator.h> #include <vespa/searchlib/test/searchiteratorverifier.h> diff --git a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp index 2eafeab20bd..87aea2e3e8c 100644 --- a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp @@ -339,29 +339,43 @@ TEST("requireThatPrefixTermsWork") { TEST("requireThatLocationTermsWork") { // 0xcc is z-curve for (10, 10). MyAttributeManager attribute_manager = makeAttributeManager(int64_t(0xcc)); - - SimpleLocationTerm node(Location(Point(10, 10), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(100, 100), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(!search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(13, 13), 4, 0), field, 0, Weight(0)); - EXPECT_TRUE(!search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(10, 13), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(search(node, attribute_manager)); + { + SimpleLocationTerm node(Location(Point{10, 10}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(search(node, attribute_manager)); + } + { + SimpleLocationTerm node(Location(Point{100, 100}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(!search(node, attribute_manager)); + } + { + SimpleLocationTerm node(Location(Point{13, 13}, 4, 0), field, 0, Weight(0)); + EXPECT_TRUE(!search(node, attribute_manager)); + } + { + SimpleLocationTerm node(Location(Point{10, 13}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(search(node, attribute_manager)); + } } TEST("requireThatOptimizedLocationTermsWork") { // 0xcc is z-curve for (10, 10). MyAttributeManager attribute_manager = makeFastSearchLongAttributeManager(int64_t(0xcc)); - - SimpleLocationTerm node(Location(Point(10, 10), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(search(node, attribute_manager, true)); - node = SimpleLocationTerm(Location(Point(100, 100), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(!search(node, attribute_manager, true)); - node = SimpleLocationTerm(Location(Point(13, 13), 4, 0), field, 0, Weight(0)); - EXPECT_TRUE(!search(node, attribute_manager, true)); - node = SimpleLocationTerm(Location(Point(10, 13), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(search(node, attribute_manager, true)); + { + SimpleLocationTerm node(Location(Point{10, 10}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(search(node, attribute_manager, true)); + } + { + SimpleLocationTerm node(Location(Point{100, 100}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(!search(node, attribute_manager, true)); + } + { + SimpleLocationTerm node(Location(Point{13, 13}, 4, 0), field, 0, Weight(0)); + EXPECT_TRUE(!search(node, attribute_manager, true)); + } + { + SimpleLocationTerm node(Location(Point{10, 13}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(search(node, attribute_manager, true)); + } } TEST("require that optimized location search works with wrapped bounding box (no hits)") { diff --git a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp index 5e633dcc97d..3098232b443 100644 --- a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp @@ -254,15 +254,22 @@ TEST(AttributeBlueprintTest, require_that_location_terms_work) { // 0xcc is z-curve for (10, 10). auto attribute_manager = makeAttributeManager(int64_t(0xcc)); - - SimpleLocationTerm node(Location(Point(10, 10), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(do_search(node, attribute_manager, false)); - node = SimpleLocationTerm(Location(Point(100, 100), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(!do_search(node, attribute_manager, false)); - node = SimpleLocationTerm(Location(Point(13, 13), 4, 0), field, 0, Weight(0)); - EXPECT_TRUE(!do_search(node, attribute_manager, false)); - node = SimpleLocationTerm(Location(Point(10, 13), 3, 0), field, 0, Weight(0)); - EXPECT_TRUE(do_search(node, attribute_manager, false)); + { + SimpleLocationTerm node(Location(Point{10, 10}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(do_search(node, attribute_manager, false)); + } + { + SimpleLocationTerm node(Location(Point{100, 100}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(!do_search(node, attribute_manager, false)); + } + { + SimpleLocationTerm node(Location(Point{13, 13}, 4, 0), field, 0, Weight(0)); + EXPECT_TRUE(!do_search(node, attribute_manager, false)); + } + { + SimpleLocationTerm node(Location(Point{10, 13}, 3, 0), field, 0, Weight(0)); + EXPECT_TRUE(do_search(node, attribute_manager, false)); + } } TEST(AttributeBlueprintTest, require_that_fast_search_location_terms_work) @@ -270,14 +277,14 @@ TEST(AttributeBlueprintTest, require_that_fast_search_location_terms_work) // 0xcc is z-curve for (10, 10). auto attribute_manager = makeFastSearchLongAttribute(int64_t(0xcc)); - SimpleLocationTerm node(Location(Point(10, 10), 3, 0), field, 0, Weight(0)); + SimpleLocationTerm node(Location(Point{10, 10}, 3, 0), field, 0, Weight(0)); #if 0 EXPECT_TRUE(search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(100, 100), 3, 0),field, 0, Weight(0)); + node = SimpleLocationTerm(Location(Point{100, 100}, 3, 0),field, 0, Weight(0)); EXPECT_TRUE(!search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(13, 13), 4, 0),field, 0, Weight(0)); + node = SimpleLocationTerm(Location(Point{13, 13}, 4, 0),field, 0, Weight(0)); EXPECT_TRUE(!search(node, attribute_manager)); - node = SimpleLocationTerm(Location(Point(10, 13), 3, 0),field, 0, Weight(0)); + node = SimpleLocationTerm(Location(Point{10, 13}, 3, 0),field, 0, Weight(0)); EXPECT_TRUE(search(node, attribute_manager)); #endif } diff --git a/searchlib/src/tests/common/location/CMakeLists.txt b/searchlib/src/tests/common/location/CMakeLists.txt index 64a894096d5..ea0d96529e1 100644 --- a/searchlib/src/tests/common/location/CMakeLists.txt +++ b/searchlib/src/tests/common/location/CMakeLists.txt @@ -1,8 +1,9 @@ # Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(searchlib_location_test_app TEST +vespa_add_executable(searchlib_geo_location_test_app TEST SOURCES - location_test.cpp + geo_location_test.cpp DEPENDS searchlib + GTest::GTest ) -vespa_add_test(NAME searchlib_location_test_app COMMAND searchlib_location_test_app) +vespa_add_test(NAME searchlib_geo_location_test_app COMMAND searchlib_geo_location_test_app) diff --git a/searchlib/src/tests/common/location/geo_location_test.cpp b/searchlib/src/tests/common/location/geo_location_test.cpp new file mode 100644 index 00000000000..8093ea61697 --- /dev/null +++ b/searchlib/src/tests/common/location/geo_location_test.cpp @@ -0,0 +1,136 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <stdio.h> +#include <vespa/searchlib/common/geo_location.h> +#include <vespa/searchlib/common/geo_location_spec.h> +#include <vespa/searchlib/common/geo_location_parser.h> +#include <vespa/vespalib/gtest/gtest.h> + +using search::common::GeoLocation; +using search::common::GeoLocationParser; + +bool is_parseable(const char *str) { + GeoLocationParser parser; + return parser.parseOldFormat(str); +} + +GeoLocation parse(const char *str) { + GeoLocationParser parser; + EXPECT_TRUE(parser.parseOldFormat(str)); + return parser.getGeoLocation(); +} + +TEST(GeoLocationTest, malformed_bounding_boxes_are_not_parseable) { + EXPECT_TRUE(is_parseable("[2,10,20,30,40]")); + EXPECT_FALSE(is_parseable("[2,10,20,30,40][2,10,20,30,40]")); + EXPECT_FALSE(is_parseable("[1,10,20,30,40]")); + EXPECT_FALSE(is_parseable("[3,10,20,30,40]")); + EXPECT_FALSE(is_parseable("[2, 10, 20, 30, 40]")); + EXPECT_FALSE(is_parseable("[2,10,20,30,40")); + EXPECT_FALSE(is_parseable("[2,10,20,30]")); + EXPECT_FALSE(is_parseable("[10,20,30,40]")); +} + +TEST(GeoLocationTest, malformed_circles_are_not_parseable) { + EXPECT_TRUE(is_parseable("(2,10,20,5,0,0,0)")); + EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0)(2,10,20,5,0,0,0)")); + EXPECT_FALSE(is_parseable("(1,10,20,5,0,0,0)")); + EXPECT_FALSE(is_parseable("(3,10,20,5,0,0,0)")); + EXPECT_FALSE(is_parseable("(2, 10, 20, 5, 0, 0, 0)")); + EXPECT_FALSE(is_parseable("(2,10,20,5)")); + EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0")); + EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0,1000")); + EXPECT_FALSE(is_parseable("(10,20,5)")); +} + +TEST(GeoLocationTest, bounding_boxes_can_be_parsed) { + auto loc = parse("[2,10,20,30,40]"); + EXPECT_EQ(false, loc.has_point); + EXPECT_EQ(true, loc.bounding_box.active()); + EXPECT_EQ(0u, loc.x_aspect.multiplier); + EXPECT_EQ(0, loc.point.x); + EXPECT_EQ(0, loc.point.y); + EXPECT_EQ(std::numeric_limits<uint32_t>::max(), loc.radius); + EXPECT_EQ(10, loc.bounding_box.x.low); + EXPECT_EQ(20, loc.bounding_box.y.low); + EXPECT_EQ(30, loc.bounding_box.x.high); + EXPECT_EQ(40, loc.bounding_box.y.high); +} + +TEST(GeoLocationTest, circles_can_be_parsed) { + auto loc = parse("(2,10,20,5,0,0,0)"); + EXPECT_EQ(true, loc.has_point); + EXPECT_EQ(true, loc.bounding_box.active()); + EXPECT_EQ(0u, loc.x_aspect.multiplier); + EXPECT_EQ(10, loc.point.x); + EXPECT_EQ(20, loc.point.y); + EXPECT_EQ(5u, loc.radius); + EXPECT_EQ(5, loc.bounding_box.x.low); + EXPECT_EQ(15, loc.bounding_box.y.low); + EXPECT_EQ(15, loc.bounding_box.x.high); + EXPECT_EQ(25, loc.bounding_box.y.high); +} + +TEST(GeoLocationTest, circles_can_have_aspect_ratio) { + auto loc = parse("(2,10,20,5,0,0,0,2147483648)"); + EXPECT_EQ(true, loc.has_point); + EXPECT_EQ(true, loc.bounding_box.active()); + EXPECT_EQ(2147483648u, loc.x_aspect.multiplier); + EXPECT_EQ(10, loc.point.x); + EXPECT_EQ(20, loc.point.y); + EXPECT_EQ(5u, loc.radius); + EXPECT_EQ(-1, loc.bounding_box.x.low); + EXPECT_EQ(15, loc.bounding_box.y.low); + EXPECT_EQ(21, loc.bounding_box.x.high); + EXPECT_EQ(25, loc.bounding_box.y.high); +} + +TEST(GeoLocationTest, bounding_box_can_be_specified_after_circle) { + auto loc = parse("(2,10,20,5,0,0,0)[2,10,20,30,40]"); + EXPECT_EQ(true, loc.has_point); + EXPECT_EQ(true, loc.bounding_box.active()); + EXPECT_EQ(0u, loc.x_aspect.multiplier); + EXPECT_EQ(10, loc.point.x); + EXPECT_EQ(20, loc.point.y); + EXPECT_EQ(5u, loc.radius); + EXPECT_EQ(10, loc.bounding_box.x.low); + EXPECT_EQ(20, loc.bounding_box.y.low); + EXPECT_EQ(15, loc.bounding_box.x.high); + EXPECT_EQ(25, loc.bounding_box.y.high); +} + +TEST(GeoLocationTest, circles_can_be_specified_after_bounding_box) { + auto loc = parse("[2,10,20,30,40](2,10,20,5,0,0,0)"); + EXPECT_EQ(true, loc.has_point); + EXPECT_EQ(true, loc.bounding_box.active()); + EXPECT_EQ(0u, loc.x_aspect.multiplier); + EXPECT_EQ(10, loc.point.x); + EXPECT_EQ(20, loc.point.y); + EXPECT_EQ(5u, loc.radius); + EXPECT_EQ(10, loc.bounding_box.x.low); + EXPECT_EQ(20, loc.bounding_box.y.low); + EXPECT_EQ(15, loc.bounding_box.x.high); + EXPECT_EQ(25, loc.bounding_box.y.high); +} + +TEST(GeoLocationTest, santa_search_gives_non_wrapped_bounding_box) { + auto loc = parse("(2,122163600,89998536,290112,4,2000,0,109704)"); + EXPECT_GE(loc.bounding_box.x.high, loc.bounding_box.x.low); + EXPECT_GE(loc.bounding_box.y.high, loc.bounding_box.y.low); +} + +TEST(GeoLocationTest, near_boundary_search_gives_non_wrapped_bounding_box) { + auto loc1 = parse("(2,2000000000,2000000000,3000000000,0,1,0)"); + EXPECT_GE(loc1.bounding_box.x.high, loc1.bounding_box.x.low); + EXPECT_GE(loc1.bounding_box.y.high, loc1.bounding_box.y.low); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high); + EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high); + + auto loc2 = parse("(2,-2000000000,-2000000000,3000000000,0,1,0)"); + EXPECT_GE(loc2.bounding_box.x.high, loc2.bounding_box.x.low); + EXPECT_GE(loc2.bounding_box.y.high, loc2.bounding_box.y.low); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.x.low); + EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.y.low); +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/common/location/location_test.cpp b/searchlib/src/tests/common/location/location_test.cpp deleted file mode 100644 index d781e5b7275..00000000000 --- a/searchlib/src/tests/common/location/location_test.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include <vespa/vespalib/testkit/test_kit.h> -#include <vespa/searchlib/common/location.h> -#include <vespa/searchlib/attribute/attributeguard.h> - - -using search::common::Location; - -bool is_parseable(const char *str) { - Location loc; - return loc.parse(str); -} - -Location parse(const char *str) { - Location loc; - if (!EXPECT_TRUE(loc.parse(str))) { - fprintf(stderr, " parse error: %s\n", loc.getParseError()); - } - return loc; -} - -TEST("require that malformed bounding boxes are not parseable") { - EXPECT_TRUE(is_parseable("[2,10,20,30,40]")); - EXPECT_FALSE(is_parseable("[2,10,20,30,40][2,10,20,30,40]")); - EXPECT_FALSE(is_parseable("[1,10,20,30,40]")); - EXPECT_FALSE(is_parseable("[3,10,20,30,40]")); - EXPECT_FALSE(is_parseable("[2, 10, 20, 30, 40]")); - EXPECT_FALSE(is_parseable("[2,10,20,30,40")); - EXPECT_FALSE(is_parseable("[2,10,20,30]")); - EXPECT_FALSE(is_parseable("[10,20,30,40]")); -} - -TEST("require that malformed circles are not parseable") { - EXPECT_TRUE(is_parseable("(2,10,20,5,0,0,0)")); - EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0)(2,10,20,5,0,0,0)")); - EXPECT_FALSE(is_parseable("(1,10,20,5,0,0,0)")); - EXPECT_FALSE(is_parseable("(3,10,20,5,0,0,0)")); - EXPECT_FALSE(is_parseable("(2, 10, 20, 5, 0, 0, 0)")); - EXPECT_FALSE(is_parseable("(2,10,20,5)")); - EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0")); - EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0,1000")); - EXPECT_FALSE(is_parseable("(10,20,5)")); -} - -TEST("require that bounding boxes can be parsed") { - Location loc = parse("[2,10,20,30,40]"); - EXPECT_EQUAL(false, loc.getRankOnDistance()); - EXPECT_EQUAL(true, loc.getPruneOnDistance()); - EXPECT_EQUAL(0u, loc.getXAspect()); - EXPECT_EQUAL(0, loc.getX()); - EXPECT_EQUAL(0, loc.getY()); - EXPECT_EQUAL(std::numeric_limits<uint32_t>::max(), loc.getRadius()); - EXPECT_EQUAL(10, loc.getMinX()); - EXPECT_EQUAL(20, loc.getMinY()); - EXPECT_EQUAL(30, loc.getMaxX()); - EXPECT_EQUAL(40, loc.getMaxY()); -} - -TEST("require that circles can be parsed") { - Location loc = parse("(2,10,20,5,0,0,0)"); - EXPECT_EQUAL(true, loc.getRankOnDistance()); - EXPECT_EQUAL(true, loc.getPruneOnDistance()); - EXPECT_EQUAL(0u, loc.getXAspect()); - EXPECT_EQUAL(10, loc.getX()); - EXPECT_EQUAL(20, loc.getY()); - EXPECT_EQUAL(5u, loc.getRadius()); - EXPECT_EQUAL(5, loc.getMinX()); - EXPECT_EQUAL(15, loc.getMinY()); - EXPECT_EQUAL(15, loc.getMaxX()); - EXPECT_EQUAL(25, loc.getMaxY()); -} - -TEST("require that circles can have aspect ratio") { - Location loc = parse("(2,10,20,5,0,0,0,2147483648)"); - EXPECT_EQUAL(true, loc.getRankOnDistance()); - EXPECT_EQUAL(true, loc.getPruneOnDistance()); - EXPECT_EQUAL(2147483648u, loc.getXAspect()); - EXPECT_EQUAL(10, loc.getX()); - EXPECT_EQUAL(20, loc.getY()); - EXPECT_EQUAL(5u, loc.getRadius()); - EXPECT_EQUAL(-1, loc.getMinX()); - EXPECT_EQUAL(15, loc.getMinY()); - EXPECT_EQUAL(21, loc.getMaxX()); - EXPECT_EQUAL(25, loc.getMaxY()); -} - -TEST("require that bounding box can be specified after circle") { - Location loc = parse("(2,10,20,5,0,0,0)[2,10,20,30,40]"); - EXPECT_EQUAL(true, loc.getRankOnDistance()); - EXPECT_EQUAL(true, loc.getPruneOnDistance()); - EXPECT_EQUAL(0u, loc.getXAspect()); - EXPECT_EQUAL(10, loc.getX()); - EXPECT_EQUAL(20, loc.getY()); - EXPECT_EQUAL(5u, loc.getRadius()); - EXPECT_EQUAL(10, loc.getMinX()); - EXPECT_EQUAL(20, loc.getMinY()); - EXPECT_EQUAL(15, loc.getMaxX()); - EXPECT_EQUAL(25, loc.getMaxY()); -} - -TEST("require that circles can be specified after bounding box") { - Location loc = parse("[2,10,20,30,40](2,10,20,5,0,0,0)"); - EXPECT_EQUAL(true, loc.getRankOnDistance()); - EXPECT_EQUAL(true, loc.getPruneOnDistance()); - EXPECT_EQUAL(0u, loc.getXAspect()); - EXPECT_EQUAL(10, loc.getX()); - EXPECT_EQUAL(20, loc.getY()); - EXPECT_EQUAL(5u, loc.getRadius()); - EXPECT_EQUAL(10, loc.getMinX()); - EXPECT_EQUAL(20, loc.getMinY()); - EXPECT_EQUAL(15, loc.getMaxX()); - EXPECT_EQUAL(25, loc.getMaxY()); -} - -TEST("require that santa search gives non-wrapped bounding box") { - Location loc = parse("(2,122163600,89998536,290112,4,2000,0,109704)"); - EXPECT_GREATER_EQUAL(loc.getMaxX(), loc.getMinX()); - EXPECT_GREATER_EQUAL(loc.getMaxY(), loc.getMinY()); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchlib/src/tests/query/query_visitor_test.cpp b/searchlib/src/tests/query/query_visitor_test.cpp index edbc29be784..8441dc2227f 100644 --- a/searchlib/src/tests/query/query_visitor_test.cpp +++ b/searchlib/src/tests/query/query_visitor_test.cpp @@ -90,7 +90,7 @@ void Test::requireThatAllNodesCanBeVisited() { checkVisit<WandTerm>(new SimpleWandTerm("field", 0, Weight(42), 57, 67, 77.7)); checkVisit<Rank>(new SimpleRank); checkVisit<NumberTerm>(new SimpleNumberTerm("0.42", "field", 0, Weight(0))); - const Location location(Point(10, 10), 20, 0); + const Location location(Point{10, 10}, 20, 0); checkVisit<LocationTerm>(new SimpleLocationTerm(location, "field", 0, Weight(0))); checkVisit<PrefixTerm>(new SimplePrefixTerm("t", "field", 0, Weight(0))); checkVisit<RangeTerm>(new SimpleRangeTerm(Range(0, 1), "field", 0, Weight(0))); diff --git a/searchlib/src/tests/query/querybuilder_test.cpp b/searchlib/src/tests/query/querybuilder_test.cpp index d093bc4242e..269600d26d4 100644 --- a/searchlib/src/tests/query/querybuilder_test.cpp +++ b/searchlib/src/tests/query/querybuilder_test.cpp @@ -32,7 +32,7 @@ const size_t distance = 4; const string int1 = "42"; const string float1 = "3.14"; const Range range(32, 64); -const Point position(100, 100); +const Point position{100, 100}; const int max_distance = 20; const uint32_t x_aspect = 0; const Location location(position, max_distance, x_aspect); diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp index 4a34a07a773..cb587d77133 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp @@ -248,11 +248,14 @@ public: LocationPostFilterBlueprint(const FieldSpec &field, const IAttributeVector &attribute, const Location &loc) : ComplexLeafBlueprint(field), _attribute(attribute), - _location() + _location(loc) { - _location.setVec(attribute); - _location.parse(loc.getLocationString()); - uint32_t estHits = _attribute.getNumDocs(); + uint32_t estHits = 0; + if (loc.valid()) { + _location.setVec(attribute); + estHits = _attribute.getNumDocs(); + } + LOG(debug, "location %s in attribute with numdocs %u", loc.getOldFormatString().c_str(), estHits); HitEstimate estimate(estHits, estHits == 0); setEstimate(estimate); } @@ -272,14 +275,16 @@ Blueprint::UP make_location_blueprint(const FieldSpec &field, const IAttributeVector &attribute, const Location &loc) { auto post_filter = std::make_unique<LocationPostFilterBlueprint>(field, attribute, loc); const common::Location &location = post_filter->location(); - if (location.getMinX() > location.getMaxX() || - location.getMinY() > location.getMaxY()) + if (location.bounding_box.x.low > location.bounding_box.x.high || + location.bounding_box.y.low > location.bounding_box.y.high) { return std::make_unique<queryeval::EmptyBlueprint>(field); } ZCurve::RangeVector rangeVector = ZCurve::find_ranges( - location.getMinX(), location.getMinY(), - location.getMaxX(), location.getMaxY()); + location.bounding_box.x.low, + location.bounding_box.y.low, + location.bounding_box.x.high, + location.bounding_box.y.high); auto pre_filter = std::make_unique<LocationPreFilterBlueprint>(field, attribute, rangeVector); if (!pre_filter->should_use()) { return post_filter; diff --git a/searchlib/src/vespa/searchlib/common/CMakeLists.txt b/searchlib/src/vespa/searchlib/common/CMakeLists.txt index 5d30260a169..7e1cfd8fec5 100644 --- a/searchlib/src/vespa/searchlib/common/CMakeLists.txt +++ b/searchlib/src/vespa/searchlib/common/CMakeLists.txt @@ -12,6 +12,9 @@ vespa_add_library(searchlib_common OBJECT featureset.cpp fileheadercontext.cpp gatecallback.cpp + geo_location.cpp + geo_location_spec.cpp + geo_location_parser.cpp growablebitvector.cpp indexmetainfo.cpp location.cpp diff --git a/searchlib/src/vespa/searchlib/common/documentlocations.cpp b/searchlib/src/vespa/searchlib/common/documentlocations.cpp index b03176f0ad2..b8f05581b41 100644 --- a/searchlib/src/vespa/searchlib/common/documentlocations.cpp +++ b/searchlib/src/vespa/searchlib/common/documentlocations.cpp @@ -21,5 +21,9 @@ DocumentLocations::setVecGuard(std::unique_ptr<search::AttributeGuard> guard) { setVec(*_vec_guard.get()->get()); } +DocumentLocations::DocumentLocations(DocumentLocations &&) = default; +DocumentLocations & DocumentLocations::operator = (DocumentLocations &&) = default; + + } // namespace common } // namespace search diff --git a/searchlib/src/vespa/searchlib/common/documentlocations.h b/searchlib/src/vespa/searchlib/common/documentlocations.h index 1dab68ca11f..51d5be76e65 100644 --- a/searchlib/src/vespa/searchlib/common/documentlocations.h +++ b/searchlib/src/vespa/searchlib/common/documentlocations.h @@ -25,8 +25,8 @@ private: const search::attribute::IAttributeVector *_vec; public: - DocumentLocations(DocumentLocations &&) = default; - DocumentLocations & operator = (DocumentLocations &&) = default; + DocumentLocations(DocumentLocations &&); + DocumentLocations & operator = (DocumentLocations &&); DocumentLocations(); virtual ~DocumentLocations(); diff --git a/searchlib/src/vespa/searchlib/common/geo_location.cpp b/searchlib/src/vespa/searchlib/common/geo_location.cpp new file mode 100644 index 00000000000..6dd7b83ae37 --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location.cpp @@ -0,0 +1,184 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "geo_location.h" + +using vespalib::geo::ZCurve; + +namespace search::common { + +namespace { + +ZCurve::BoundingBox to_z(GeoLocation::Box box) { + return ZCurve::BoundingBox(box.x.low, box.x.high, + box.y.low, box.y.high); +} + +GeoLocation::Box +adjust_bounding_box(GeoLocation::Box orig, GeoLocation::Point point, uint32_t radius, GeoLocation::Aspect x_aspect) +{ + if (radius == GeoLocation::radius_inf) { + // only happens if GeoLocation is explicitly constructed with "infinite" radius + return orig; + } + uint32_t maxdx = radius; + if (x_aspect.active()) { + // x_aspect is a 32-bit fixed-point number in range [0,1] + // so this implements maxdx = ceil(radius/x_aspect) + uint64_t maxdx2 = ((static_cast<uint64_t>(radius) << 32) + 0xffffffffu) / x_aspect.multiplier; + if (maxdx2 >= 0xffffffffu) { + maxdx = 0xffffffffu; + } else { + maxdx = static_cast<uint32_t>(maxdx2); + } + } + // implied limits from radius and point: + int64_t implied_max_x = int64_t(point.x) + int64_t(maxdx); + int64_t implied_min_x = int64_t(point.x) - int64_t(maxdx); + + int64_t implied_max_y = int64_t(point.y) + int64_t(radius); + int64_t implied_min_y = int64_t(point.y) - int64_t(radius); + + int32_t max_x = orig.x.high; + int32_t min_x = orig.x.low; + + int32_t max_y = orig.y.high; + int32_t min_y = orig.y.low; + + if (implied_max_x < max_x) max_x = implied_max_x; + if (implied_min_x > min_x) min_x = implied_min_x; + + if (implied_max_y < max_y) max_y = implied_max_y; + if (implied_min_y > min_y) min_y = implied_min_y; + + return GeoLocation::Box{GeoLocation::Range{min_x, max_x}, + GeoLocation::Range{min_y, max_y}}; +} + +} // namespace <unnamed> + +GeoLocation::GeoLocation() + : has_point(false), + point{0, 0}, + radius(radius_inf), + x_aspect(), + bounding_box(no_box), + _sq_radius(sq_radius_inf), + _z_bounding_box(0,0,0,0) +{} + +GeoLocation::GeoLocation(Point p) + : has_point(true), + point(p), + radius(radius_inf), + x_aspect(), + bounding_box(no_box), + _sq_radius(sq_radius_inf), + _z_bounding_box(0,0,0,0) +{} + +GeoLocation::GeoLocation(Point p, Aspect xa) + : has_point(true), + point(p), + radius(radius_inf), + x_aspect(xa), + bounding_box(no_box), + _sq_radius(sq_radius_inf), + _z_bounding_box(0,0,0,0) +{} + +GeoLocation::GeoLocation(Point p, uint32_t r) + : has_point(true), + point(p), + radius(r), + x_aspect(), + bounding_box(adjust_bounding_box(no_box, p, r, Aspect())), + _sq_radius(uint64_t(r) * uint64_t(r)), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Point p, uint32_t r, Aspect xa) + : has_point(true), + point(p), + radius(r), + x_aspect(xa), + bounding_box(adjust_bounding_box(no_box, p, r, xa)), + _sq_radius(uint64_t(r) * uint64_t(r)), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Box b) + : has_point(false), + point{0, 0}, + radius(radius_inf), + x_aspect(), + bounding_box(b), + _sq_radius(sq_radius_inf), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Box b, Point p) + : has_point(true), + point(p), + radius(radius_inf), + x_aspect(), + bounding_box(b), + _sq_radius(sq_radius_inf), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Box b, Point p, Aspect xa) + : has_point(true), + point(p), + radius(radius_inf), + x_aspect(xa), + bounding_box(b), + _sq_radius(sq_radius_inf), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Box b, Point p, uint32_t r) + : has_point(true), + point(p), + radius(r), + x_aspect(), + bounding_box(adjust_bounding_box(b, p, r, Aspect())), + _sq_radius(uint64_t(r) * uint64_t(r)), + _z_bounding_box(to_z(bounding_box)) +{} + +GeoLocation::GeoLocation(Box b, Point p, uint32_t r, Aspect xa) + : has_point(true), + point(p), + radius(r), + x_aspect(xa), + bounding_box(adjust_bounding_box(b, p, r, xa)), + _sq_radius(uint64_t(r) * uint64_t(r)), + _z_bounding_box(to_z(bounding_box)) +{} + +uint64_t GeoLocation::sq_distance_to(Point p) const { + if (has_point) { + uint64_t dx = (p.x > point.x) ? (p.x - point.x) : (point.x - p.x); + if (x_aspect.active()) { + // x_aspect is a 32-bit fixed-point number in range [0,1] + // this implements dx = (dx * x_aspect) + dx = (dx * x_aspect.multiplier) >> 32; + } + uint64_t dy = (p.y > point.y) ? (p.y - point.y) : (point.y - p.y); + return dx*dx + dy*dy; + } + return 0; +} + +bool GeoLocation::inside_limit(Point p) const { + if (p.x < bounding_box.x.low) return false; + if (p.x > bounding_box.x.high) return false; + + if (p.y < bounding_box.y.low) return false; + if (p.y > bounding_box.y.high) return false; + + uint64_t sq_dist = sq_distance_to(p); + return sq_dist <= _sq_radius; +} + +} // namespace search::common diff --git a/searchlib/src/vespa/searchlib/common/geo_location.h b/searchlib/src/vespa/searchlib/common/geo_location.h new file mode 100644 index 00000000000..5d04a09142a --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location.h @@ -0,0 +1,90 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <string> +#include <cstdint> +#include <limits> +#include <vespa/vespalib/geo/zcurve.h> + +namespace search::common { + +/** + * An immutable struct for a (geo) location. + * Contains a point with optional radius, a bounding box, or both. + **/ +struct GeoLocation +{ + // contained structs and helper constants: + static constexpr int32_t range_low = std::numeric_limits<int32_t>::min(); + static constexpr int32_t range_high = std::numeric_limits<int32_t>::max(); + static constexpr uint32_t radius_inf = std::numeric_limits<uint32_t>::max(); + struct Point { + const int32_t x; + const int32_t y; + Point() = delete; + }; + struct Aspect { + uint32_t multiplier; + Aspect() : multiplier(0) {} + Aspect(uint32_t multiplier_in) : multiplier(multiplier_in) {} + bool active() const { return multiplier != 0; } + }; + struct Range { + const int32_t low; + const int32_t high; + bool active() const { + return (low != range_low) || (high != range_high); + } + }; + static constexpr Range no_range = {range_low, range_high}; + struct Box { + const Range x; + const Range y; + bool active() const { return x.active() || y.active(); } + }; + static constexpr Box no_box = {no_range, no_range}; + + // actual content of struct: + const bool has_point; + Point point; + uint32_t radius; + Aspect x_aspect; + Box bounding_box; + GeoLocation(); + + // constructors: + GeoLocation(Point p); + GeoLocation(Point p, Aspect xa); + GeoLocation(Point p, uint32_t r); + GeoLocation(Point p, uint32_t r, Aspect xa); + GeoLocation(Box b); + GeoLocation(Box b, Point p); + GeoLocation(Box b, Point p, Aspect xa); + GeoLocation(Box b, Point p, uint32_t r); + GeoLocation(Box b, Point p, uint32_t r, Aspect xa); + + // helper methods: + bool has_radius() const { return radius != radius_inf; } + bool valid() const { return has_point || bounding_box.active(); } + bool can_limit() const { return bounding_box.active(); } + + uint64_t sq_distance_to(Point p) const; + bool inside_limit(Point p) const; + + bool inside_limit(int64_t zcurve_encoded_xy) const { + if (_z_bounding_box.getzFailBoundingBoxTest(zcurve_encoded_xy)) return false; + int32_t x = 0; + int32_t y = 0; + vespalib::geo::ZCurve::decode(zcurve_encoded_xy, &x, &y); + return inside_limit(Point{x, y}); + } + +private: + // constants for implementation of helper methods: + static constexpr uint64_t sq_radius_inf = std::numeric_limits<uint64_t>::max(); + const uint64_t _sq_radius; + const vespalib::geo::ZCurve::BoundingBox _z_bounding_box; +}; + +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp new file mode 100644 index 00000000000..05c53348699 --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp @@ -0,0 +1,209 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "geo_location_parser.h" +#include <limits> +#include <vespa/vespalib/stllike/asciistream.h> + +namespace { + +int getInt(const char * &p) { + int val; + bool isminus; + val = 0; + isminus = false; + if (*p == '-') { + isminus = true; + p++; + } + while (*p >= '0' && *p <= '9') { + val *= 10; + val += (*p++ - '0'); + } + return isminus ? - val : val; +} + +} // namespace <unnamed> + +namespace search::common { + +GeoLocationParser::GeoLocationParser() + : _valid(false), + _has_point(false), + _has_bounding_box(false), + _field_name(), + _x(0), + _y(0), + _x_aspect(0u), + _radius(std::numeric_limits<uint32_t>::max()), + _min_x(std::numeric_limits<int32_t>::min()), + _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) +{} + +bool +GeoLocationParser::correctDimensionalitySkip(const char * &p) { + if (*p == '2') { + p++; + if (*p != ',') { + _parseError = "Missing comma after 2D dimensionality"; + return false; + } + p++; + return true; + } + _parseError = "Bad dimensionality spec, not 2D"; + return false; +} + +bool +GeoLocationParser::parseOldFormatWithField(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 parseOldFormat(only_loc); +} + +bool +GeoLocationParser::parseOldFormat(const std::string &locStr) +{ + bool foundBoundingBox = false; + bool foundLoc = false; + const char *p = locStr.c_str(); + while (*p != '\0') { + if (*p == '[') { + p++; + if (foundBoundingBox) { + _parseError = "Duplicate bounding box"; + return false; + } + foundBoundingBox = true; + if (!correctDimensionalitySkip(p)) { + return false; + } + _min_x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after minx"; + return false; + } + p++; + _min_y = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after miny"; + return false; + } + p++; + _max_x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after maxx"; + return false; + } + p++; + _max_y = getInt(p); + if (*p != ']') { + _parseError = "Missing ']' after maxy"; + return false; + } + p++; + } else if (*p == '(') { + p++; + if (foundLoc) { + _parseError = "Duplicate location"; + return false; + } + foundLoc = true; + if (!correctDimensionalitySkip(p)) { + return false; + } + _x = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after x position"; + return false; + } + p++; + _y = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after y position"; + return false; + } + p++; + _radius = getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after radius"; + return false; + } + p++; + /* _tableID = */ (void) getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after tableID"; + return false; + } + p++; + /* _rankMultiplier = */ (void) getInt(p); + if (*p != ',') { + _parseError = "Missing ',' after rank multiplier"; + return false; + } + p++; + /* _rankOnlyOnDistance = */ (void) getInt(p); + if (*p == ',') { + p++; + _x_aspect = getInt(p); + if (*p != ')') { + _parseError = "Missing ')' after xAspect"; + return false; + } + } else { + if (*p != ')') { + _parseError = "Missing ')' after rankOnlyOnDistance flag"; + return false; + } + } + p++; + } else if (*p == ' ') { + p++; + } else { + _parseError = "Unexpected char in location spec"; + return false; + } + } + _has_point = foundLoc; + _has_bounding_box = foundBoundingBox; + _valid = (_has_point || _has_bounding_box); + return _valid; +} + +GeoLocation +GeoLocationParser::getGeoLocation() const +{ + GeoLocation::Aspect aspect(_x_aspect); + if (_has_bounding_box) { + GeoLocation::Range x_range{_min_x, _max_x}; + GeoLocation::Range y_range{_min_y, _max_y}; + GeoLocation::Box bounding_box{x_range, y_range}; + if (_has_point) { + GeoLocation::Point point{_x, _y}; + if (_radius == GeoLocation::radius_inf) { + return GeoLocation(bounding_box, point, aspect); + } + return GeoLocation(bounding_box, point, _radius, aspect); + } + return GeoLocation(bounding_box); + } + if (_has_point) { + GeoLocation::Point point{_x, _y}; + if (_radius == GeoLocation::radius_inf) { + return GeoLocation(point, aspect); + } + return GeoLocation(point, _radius, aspect); + } + return GeoLocation(); +} + +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.h b/searchlib/src/vespa/searchlib/common/geo_location_parser.h new file mode 100644 index 00000000000..8936a620d21 --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.h @@ -0,0 +1,47 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <string> +#include <cstdint> +#include "geo_location.h" +#include "geo_location_spec.h" + +namespace search::common { + +/** + * Parser for a geo-location string representation. + **/ +class GeoLocationParser +{ +public: + GeoLocationParser(); + + bool parseOldFormat(const std::string &locStr); + bool parseOldFormatWithField(const std::string &str); + + std::string getFieldName() const { return _field_name; } + GeoLocation getGeoLocation() const; + + const char * getParseError() const { return _parseError; } +private: + bool _valid; + bool _has_point; + bool _has_bounding_box; + + std::string _field_name; + + int32_t _x; /* Query X position */ + int32_t _y; /* Query Y position */ + uint32_t _x_aspect; /* X distance multiplier fraction */ + uint32_t _radius; /* Radius for euclidean distance */ + int32_t _min_x; /* Min X coordinate */ + int32_t _max_x; /* Max X coordinate */ + int32_t _min_y; /* Min Y coordinate */ + int32_t _max_y; /* Max Y coordinate */ + + const char *_parseError; + bool correctDimensionalitySkip(const char * &p); +}; + +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/geo_location_spec.cpp b/searchlib/src/vespa/searchlib/common/geo_location_spec.cpp new file mode 100644 index 00000000000..271946e2df6 --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_spec.cpp @@ -0,0 +1,3 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "geo_location_spec.h" diff --git a/searchlib/src/vespa/searchlib/common/geo_location_spec.h b/searchlib/src/vespa/searchlib/common/geo_location_spec.h new file mode 100644 index 00000000000..42c2b8e6c8c --- /dev/null +++ b/searchlib/src/vespa/searchlib/common/geo_location_spec.h @@ -0,0 +1,21 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <string> +#include <cstdint> +#include "geo_location.h" + +namespace search::common { + +/** + * Immutable specification of a geo-location query item. + **/ +struct GeoLocationSpec +{ +public: + const std::string field_name; + const GeoLocation location; +}; + +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/location.cpp b/searchlib/src/vespa/searchlib/common/location.cpp index 6927d9ab6cb..171dcecaa33 100644 --- a/searchlib/src/vespa/searchlib/common/location.cpp +++ b/searchlib/src/vespa/searchlib/common/location.cpp @@ -5,198 +5,6 @@ namespace search::common { -Location::Location() : - _zBoundingBox(0,0,0,0), - _x(0), - _y(0), - _xAspect(0u), - _radius(std::numeric_limits<uint32_t>::max()), - _minx(std::numeric_limits<int32_t>::min()), - _maxx(std::numeric_limits<int32_t>::max()), - _miny(std::numeric_limits<int32_t>::min()), - _maxy(std::numeric_limits<int32_t>::max()), - _rankOnDistance(false), - _pruneOnDistance(false), - _parseError(NULL) -{ -} +Location::Location(const GeoLocation &from) : GeoLocation(from) {} - -bool -Location::getDimensionality(const char **pp) -{ - if (**pp == '2') { - (*pp)++; - if (**pp != ',') { - _parseError = "Missing comma after 2D dimensionality"; - return false; - } - (*pp)++; - return true; - } - _parseError = "Bad dimensionality spec, not 2D"; - return false; -} - - -int -Location::getInt(const char **pp) -{ - const char *p = *pp; - int val; - bool isminus; - - val = 0; - isminus = false; - if (*p == '-') { - isminus = true; - p++; - } - while (*p >= '0' && *p <= '9') - val = val * 10 + *p++ - '0'; - *pp = p; - return isminus ? - val : val; -} - -bool Location::parse(const vespalib::string &locStr) -{ - bool hadCutoff = false; - bool hadLoc = false; - const char *p = locStr.c_str(); - while (*p != '\0') { - if (*p == '[') { - p++; - if (hadCutoff) { - _parseError = "Duplicate square cutoff"; - return false; - } - hadCutoff = true; - if (!getDimensionality(&p)) - return false; - _minx = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after minx"; - return false; - } - p++; - _miny = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after miny"; - return false; - } - p++; - _maxx = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after maxx"; - return false; - } - p++; - _maxy = getInt(&p); - if (*p != ']') { - _parseError = "Missing ']' after maxy"; - return false; - } - p++; - } else if (*p == '(') { - p++; - if (hadLoc) { - _parseError = "Duplicate location"; - return false; - } - hadLoc = true; - if (!getDimensionality(&p)) - return false; - _x = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after x position"; - return false; - } - p++; - _y = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after y position"; - return false; - } - p++; - _radius = getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after radius"; - return false; - } - p++; - /* _tableID = */ (void) getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after tableID"; - return false; - } - p++; - /* _rankMultiplier = */ (void) getInt(&p); - if (*p != ',') { - _parseError = "Missing ',' after rank multiplier"; - return false; - } - p++; - /* _rankOnlyOnDistance = */ (void) (getInt(&p) != 0); - if (*p == ',') { - p++; - _xAspect = getInt(&p); - if (*p != ')') { - _parseError = "Missing ')' after xAspect"; - return false; - } - } else { - if (*p != ')') { - _parseError = "Missing ')' after rankOnlyOnDistance flag"; - return false; - } - } - p++; - } else if (*p == ' ') - p++; - else { - _parseError = "Unexpected char in location spec"; - return false; - } - } - - if (hadLoc) { - _rankOnDistance = true; - uint32_t maxdx = _radius; - if (_xAspect != 0) { - uint64_t maxdx2 = ((static_cast<uint64_t>(_radius) << 32) + 0xffffffffu) / - _xAspect; - if (maxdx2 >= 0xffffffffu) - maxdx = 0xffffffffu; - else - maxdx = static_cast<uint32_t>(maxdx2); - } - if (static_cast<int32_t>(_x - maxdx) > _minx && - static_cast<int64_t>(_x) - static_cast<int64_t>(maxdx) > - static_cast<int64_t>(_minx)) - _minx = _x - maxdx; - if (static_cast<int32_t>(_x + maxdx) < _maxx && - static_cast<int64_t>(_x) + static_cast<int64_t>(maxdx) < - static_cast<int64_t>(_maxx)) - _maxx = _x + maxdx; - if (static_cast<int32_t>(_y - _radius) > _miny && - static_cast<int64_t>(_y) - static_cast<int64_t>(_radius) > - static_cast<int64_t>(_miny)) - _miny = _y - _radius; - if (static_cast<int32_t>(_y + _radius) < _maxy && - static_cast<int64_t>(_y) + static_cast<int64_t>(_radius) < - static_cast<int64_t>(_maxy)) - _maxy = _y + _radius; - } - if (_minx != std::numeric_limits<int32_t>::min() || - _maxx != std::numeric_limits<int32_t>::max() || - _miny != std::numeric_limits<int32_t>::min() || - _maxy != std::numeric_limits<int32_t>::max()) - { - _pruneOnDistance = true; - } - _zBoundingBox = vespalib::geo::ZCurve::BoundingBox(_minx, _maxx, _miny, _maxy); - - return true; -} - -} +} // namespace diff --git a/searchlib/src/vespa/searchlib/common/location.h b/searchlib/src/vespa/searchlib/common/location.h index a00bb83648a..197f92326cd 100644 --- a/searchlib/src/vespa/searchlib/common/location.h +++ b/searchlib/src/vespa/searchlib/common/location.h @@ -3,51 +3,19 @@ #pragma once #include "documentlocations.h" -#include <vespa/vespalib/geo/zcurve.h> - -#include <vespa/vespalib/stllike/string.h> +#include "geo_location.h" namespace search::common { -class Location : public DocumentLocations +class Location : public DocumentLocations, + public GeoLocation { -private: - static int getInt(const char **pp); - bool getDimensionality(const char **pp); - public: - Location(); - bool getRankOnDistance() const { return _rankOnDistance; } - bool getPruneOnDistance() const { return _pruneOnDistance; } - uint32_t getXAspect() const { return _xAspect; } - int32_t getX() const { return _x; } - int32_t getY() const { return _y; } - uint32_t getRadius() const { return _radius; } - const char * getParseError() const { return _parseError; } - int32_t getMinX() const { return _minx; } - int32_t getMinY() const { return _miny; } - int32_t getMaxX() const { return _maxx; } - int32_t getMaxY() const { return _maxy; } - bool getzFailBoundingBoxTest(int64_t docxy) const { - return _zBoundingBox.getzFailBoundingBoxTest(docxy); - } - - bool parse(const vespalib::string &locStr); - -private: - vespalib::geo::ZCurve::BoundingBox _zBoundingBox; - int32_t _x; /* Query X position */ - int32_t _y; /* Query Y position */ - uint32_t _xAspect; /* X distance multiplier fraction */ - uint32_t _radius; /* Radius for euclidean distance */ - int32_t _minx; /* Min X coordinate */ - int32_t _maxx; /* Max X coordinate */ - int32_t _miny; /* Min Y coordinate */ - int32_t _maxy; /* Max Y coordinate */ - - bool _rankOnDistance; - bool _pruneOnDistance; - const char *_parseError; + Location(const GeoLocation& from); + ~Location() {} + Location(Location &&) = default; + bool getRankOnDistance() const { return has_point; } + bool getPruneOnDistance() const { return can_limit(); } }; } diff --git a/searchlib/src/vespa/searchlib/common/locationiterators.cpp b/searchlib/src/vespa/searchlib/common/locationiterators.cpp index 16e465bcd05..d90ed3b41f3 100644 --- a/searchlib/src/vespa/searchlib/common/locationiterators.cpp +++ b/searchlib/src/vespa/searchlib/common/locationiterators.cpp @@ -4,6 +4,9 @@ #include <vespa/searchlib/bitcompression/compression.h> #include <vespa/searchlib/attribute/attributevector.h> +#include <vespa/log/log.h> +LOG_SETUP(".searchlib.common.locationiterators"); + using namespace search::common; class FastS_2DZLocationIterator : public search::queryeval::SearchIterator @@ -11,7 +14,6 @@ class FastS_2DZLocationIterator : public search::queryeval::SearchIterator private: const unsigned int _numDocs; const bool _strict; - const uint64_t _radius2; const Location & _location; std::vector<search::AttributeVector::largeint_t> _pos; @@ -31,7 +33,6 @@ FastS_2DZLocationIterator(unsigned int numDocs, : SearchIterator(), _numDocs(numDocs), _strict(strict), - _radius2(static_cast<uint64_t>(location.getRadius()) * location.getRadius()), _location(location), _pos() { @@ -45,6 +46,8 @@ FastS_2DZLocationIterator::~FastS_2DZLocationIterator() = default; void FastS_2DZLocationIterator::doSeek(uint32_t docId) { + LOG(debug, "FastS_2DZLocationIterator: seek(%u) with numDocs=%u endId=%u", + docId, _numDocs, getEndId()); if (__builtin_expect(docId >= _numDocs, false)) { setAtEnd(); return; @@ -62,24 +65,9 @@ FastS_2DZLocationIterator::doSeek(uint32_t docId) } for (uint32_t i = 0; i < numValues; i++) { int64_t docxy(pos[i]); - if ( ! location.getzFailBoundingBoxTest(docxy)) { - int32_t docx = 0; - int32_t docy = 0; - vespalib::geo::ZCurve::decode(docxy, &docx, &docy); - uint32_t dx = (location.getX() > docx) - ? location.getX() - docx - : docx - location.getX(); - if (location.getXAspect() != 0) - dx = ((uint64_t) dx * location.getXAspect()) >> 32; - - uint32_t dy = (location.getY() > docy) - ? location.getY() - docy - : docy - location.getY(); - uint64_t dist2 = (uint64_t) dx * dx + (uint64_t) dy * dy; - if (dist2 <= _radius2) { - setDocId(docId); - return; - } + if (location.inside_limit(docxy)) { + setDocId(docId); + return; } } diff --git a/searchlib/src/vespa/searchlib/features/distancefeature.cpp b/searchlib/src/vespa/searchlib/features/distancefeature.cpp index 7a624e64d67..bd2c7becc81 100644 --- a/searchlib/src/vespa/searchlib/features/distancefeature.cpp +++ b/searchlib/src/vespa/searchlib/features/distancefeature.cpp @@ -82,7 +82,8 @@ ConvertRawscoreToDistance::execute(uint32_t docId) feature_t DistanceExecutor::calculateDistance(uint32_t docId) { - if (_location.isValid() && _pos != nullptr) { + if ((! _locations.empty()) && (_pos != nullptr)) { + LOG(debug, "calculate 2D Z-distance from %zu locations", _locations.size()); return calculate2DZDistance(docId); } return DEFAULT_DISTANCE; @@ -97,35 +98,33 @@ DistanceExecutor::calculate2DZDistance(uint32_t docId) uint64_t sqabsdist = std::numeric_limits<uint64_t>::max(); int32_t docx = 0; int32_t docy = 0; - for (uint32_t i = 0; i < numValues; ++i) { - vespalib::geo::ZCurve::decode(_intBuf[i], &docx, &docy); - uint32_t dx; - uint32_t dy; - if (_location.getXPosition() > docx) { - dx = _location.getXPosition() - docx; - } else { - dx = docx - _location.getXPosition(); - } - if (_location.getXAspect() != 0) { - dx = ((uint64_t) dx * _location.getXAspect()) >> 32; - } - if (_location.getYPosition() > docy) { - dy = _location.getYPosition() - docy; - } else { - dy = docy - _location.getYPosition(); - } - uint64_t sqdist = (uint64_t) dx * dx + (uint64_t) dy * dy; - if (sqdist < sqabsdist) { - sqabsdist = sqdist; + for (auto loc : _locations) { + assert(loc); + assert(loc->isValid()); + int32_t loc_x = loc->getXPosition(); + int32_t loc_y = loc->getYPosition(); + uint64_t loc_a = loc->getXAspect(); + LOG(debug, "location: x=%u, y=%u, aspect=%zu", loc_x, loc_y, loc_a); + for (uint32_t i = 0; i < numValues; ++i) { + vespalib::geo::ZCurve::decode(_intBuf[i], &docx, &docy); + uint32_t dx = (loc_x > docx) ? (loc_x - docx) : (docx - loc_x); + if (loc_a != 0) { + dx = (uint64_t(dx) * loc_a) >> 32; + } + uint32_t dy = (loc_y > docy) ? (loc_y - docy) : (docy - loc_y); + uint64_t sqdist = (uint64_t) dx * dx + (uint64_t) dy * dy; + if (sqdist < sqabsdist) { + sqabsdist = sqdist; + } } } return static_cast<feature_t>(std::sqrt(static_cast<feature_t>(sqabsdist))); } -DistanceExecutor::DistanceExecutor(const Location & location, +DistanceExecutor::DistanceExecutor(std::vector<const Location *> locations, const search::attribute::IAttributeVector * pos) : FeatureExecutor(), - _location(location), + _locations(locations), _pos(pos), _intBuf() { @@ -231,6 +230,7 @@ DistanceBlueprint::setup(const IIndexEnvironment & env, return setup_geopos(env, z); } if (allow_bad_field) { + // TODO remove on Vespa 8 // backwards compatibility fallback: return setup_geopos(env, arg); } @@ -251,11 +251,30 @@ DistanceBlueprint::createExecutor(const IQueryEnvironment &env, vespalib::Stash if (_use_item_label) { return stash.create<ConvertRawscoreToDistance>(env, _arg_string); } + // expect geo pos: const search::attribute::IAttributeVector * pos = nullptr; - const Location & location = env.getLocation(); - LOG(debug, "DistanceBlueprint::createExecutor location.valid='%s', attribute='%s'", - location.isValid() ? "true" : "false", _arg_string.c_str()); - if (_use_geo_pos && location.isValid()) { + std::vector<const search::fef::Location *> matching_locs; + std::vector<const search::fef::Location *> other_locs; + + for (auto loc_ptr : env.getAllLocations()) { + if (_use_geo_pos && loc_ptr && loc_ptr->isValid()) { + if (loc_ptr->getAttribute() == _arg_string) { + LOG(debug, "found loc from query env matching '%s'", _arg_string.c_str()); + matching_locs.push_back(loc_ptr); + } else { + LOG(debug, "found loc(%s) from query env not matching arg(%s)", + loc_ptr->getAttribute().c_str(), _arg_string.c_str()); + other_locs.push_back(loc_ptr); + } + } + } + if (matching_locs.empty() && other_locs.empty()) { + LOG(debug, "createExecutor: no valid locations"); + return stash.create<DistanceExecutor>(matching_locs, nullptr); + } + LOG(debug, "createExecutor: valid location, attribute='%s'", _arg_string.c_str()); + + if (_use_geo_pos) { pos = env.getAttributeContext().getAttribute(_arg_string); if (pos != nullptr) { if (!pos->isIntegerType()) { @@ -271,8 +290,8 @@ DistanceBlueprint::createExecutor(const IQueryEnvironment &env, vespalib::Stash LOG(warning, "The position attribute '%s' was not found. Will use default distance.", _arg_string.c_str()); } } - - return stash.create<DistanceExecutor>(location, pos); + LOG(debug, "use '%s' locations with pos=%p", matching_locs.empty() ? "other" : "matching", pos); + return stash.create<DistanceExecutor>(matching_locs.empty() ? other_locs : matching_locs, pos); } } diff --git a/searchlib/src/vespa/searchlib/features/distancefeature.h b/searchlib/src/vespa/searchlib/features/distancefeature.h index 3a8edd5ee94..024b9f37f31 100644 --- a/searchlib/src/vespa/searchlib/features/distancefeature.h +++ b/searchlib/src/vespa/searchlib/features/distancefeature.h @@ -12,7 +12,7 @@ namespace search::features { */ class DistanceExecutor : public fef::FeatureExecutor { private: - const fef::Location & _location; + std::vector<const fef::Location *> _locations; const attribute::IAttributeVector * _pos; attribute::IntegerContent _intBuf; @@ -23,10 +23,11 @@ public: /** * Constructs an executor for the distance feature. * - * @param location the location object associated with the query environment. + * @param locations location objects associated with the query environment. * @param pos the attribute to use for positions (expects zcurve encoding). */ - DistanceExecutor(const fef::Location & location, const attribute::IAttributeVector * pos); + DistanceExecutor(std::vector<const fef::Location *> locations, + const attribute::IAttributeVector * pos); void execute(uint32_t docId) override; static const feature_t DEFAULT_DISTANCE; diff --git a/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h b/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h index 041e9ec67bc..811e7fd4616 100644 --- a/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h +++ b/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h @@ -58,9 +58,9 @@ public: /** * Obtain the location information associated with this query environment. * - * @return location object. + * @return pointers to location objects. **/ - virtual const Location & getLocation() const = 0; + virtual std::vector<const Location *> getAllLocations() const = 0; /** * Returns the attribute context for this query. diff --git a/searchlib/src/vespa/searchlib/fef/location.h b/searchlib/src/vespa/searchlib/fef/location.h index 5be7d1ce822..3bc693e11b4 100644 --- a/searchlib/src/vespa/searchlib/fef/location.h +++ b/searchlib/src/vespa/searchlib/fef/location.h @@ -39,7 +39,7 @@ public: } /** - * Returns the name of the attribute to use for x positions. + * Returns the name of the attribute to use for positions. * * @return the attribute name. **/ diff --git a/searchlib/src/vespa/searchlib/fef/phrase_splitter_query_env.h b/searchlib/src/vespa/searchlib/fef/phrase_splitter_query_env.h index b2a3d416f5a..3a8cde99c06 100644 --- a/searchlib/src/vespa/searchlib/fef/phrase_splitter_query_env.h +++ b/searchlib/src/vespa/searchlib/fef/phrase_splitter_query_env.h @@ -73,7 +73,9 @@ public: } const Properties & getProperties() const override { return _queryEnv.getProperties(); } - const Location & getLocation() const override { return _queryEnv.getLocation(); } + std::vector<const Location *> getAllLocations() const override { + return _queryEnv.getAllLocations(); + } const attribute::IAttributeContext & getAttributeContext() const override { return _queryEnv.getAttributeContext(); } double get_average_field_length(const vespalib::string &field_name) const override { return _queryEnv.get_average_field_length(field_name); } const IIndexEnvironment & getIndexEnvironment() const override { return _queryEnv.getIndexEnvironment(); } diff --git a/searchlib/src/vespa/searchlib/fef/test/queryenvironment.h b/searchlib/src/vespa/searchlib/fef/test/queryenvironment.h index 40898281794..4b9bec1ee68 100644 --- a/searchlib/src/vespa/searchlib/fef/test/queryenvironment.h +++ b/searchlib/src/vespa/searchlib/fef/test/queryenvironment.h @@ -38,7 +38,11 @@ public: const Properties &getProperties() const override { return _properties; } uint32_t getNumTerms() const override { return _terms.size(); } const ITermData *getTerm(uint32_t idx) const override { return idx < _terms.size() ? &_terms[idx] : NULL; } - const Location & getLocation() const override { return _location; } + std::vector<const Location *> getAllLocations() const override { + std::vector<const Location *> retval; + retval.push_back(&_location); + return retval; + } const search::attribute::IAttributeContext &getAttributeContext() const override { return *_attrCtx; } double get_average_field_length(const vespalib::string& field_name) const override { auto itr = _avg_field_lengths.find(field_name); diff --git a/searchlib/src/vespa/searchlib/parsequery/parse.h b/searchlib/src/vespa/searchlib/parsequery/parse.h index b4dd9826b84..68e259b92e8 100644 --- a/searchlib/src/vespa/searchlib/parsequery/parse.h +++ b/searchlib/src/vespa/searchlib/parsequery/parse.h @@ -53,7 +53,7 @@ public: ITEM_REGEXP = 24, ITEM_WORD_ALTERNATIVES = 25, ITEM_NEAREST_NEIGHBOR = 26, - ITEM_LOCATION_TERM = 27, + ITEM_GEO_LOCATION_TERM = 27, ITEM_MAX = 28, // Indicates how long tables must be. ITEM_UNDEF = 31, }; diff --git a/searchlib/src/vespa/searchlib/parsequery/stackdumpiterator.cpp b/searchlib/src/vespa/searchlib/parsequery/stackdumpiterator.cpp index 17cbd6dce1b..1820fb0e969 100644 --- a/searchlib/src/vespa/searchlib/parsequery/stackdumpiterator.cpp +++ b/searchlib/src/vespa/searchlib/parsequery/stackdumpiterator.cpp @@ -207,7 +207,7 @@ SimpleQueryStackDumpIterator::next() } break; case ParseItem::ITEM_NUMTERM: - case ParseItem::ITEM_LOCATION_TERM: + case ParseItem::ITEM_GEO_LOCATION_TERM: case ParseItem::ITEM_TERM: case ParseItem::ITEM_PREFIXTERM: case ParseItem::ITEM_SUBSTRINGTERM: diff --git a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp index f1599e820ef..66466b030d0 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp +++ b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp @@ -63,8 +63,13 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor } } break; + case ParseItem::ITEM_GEO_LOCATION_TERM: + // TODO implement this: + // vespalib::string field = queryRep.getIndexName(); + // vespalib::stringref location_term = queryRep.getTerm(); + // qn = std::make_unique<LocationQueryNode> ...something .... + // break; case ParseItem::ITEM_NUMTERM: - case ParseItem::ITEM_LOCATION_TERM: case ParseItem::ITEM_TERM: case ParseItem::ITEM_PREFIXTERM: case ParseItem::ITEM_REGEXP: diff --git a/searchlib/src/vespa/searchlib/query/tree/location.cpp b/searchlib/src/vespa/searchlib/query/tree/location.cpp index 216c5ec5ad0..6e678f9e682 100644 --- a/searchlib/src/vespa/searchlib/query/tree/location.cpp +++ b/searchlib/src/vespa/searchlib/query/tree/location.cpp @@ -6,58 +6,71 @@ #include <vespa/vespalib/stllike/asciistream.h> using vespalib::asciistream; +using search::common::GeoLocation; namespace search::query { -Location::Location(const Point &point, uint32_t max_dist, uint32_t x_aspect) { - asciistream loc; - loc << "(2" // dimensionality - << "," << point.x - << "," << point.y - << "," << max_dist - << "," << "0" // table id. - << "," << "1" // rank multiplier. - << "," << "0" // rank only on distance. - << "," << x_aspect // x aspect. - << ")"; - _location_string = loc.str(); +static GeoLocation::Box convert(const Rectangle &rect) { + GeoLocation::Range x_range{rect.left, rect.right}; + GeoLocation::Range y_range{rect.top, rect.bottom}; + return GeoLocation::Box{x_range, y_range}; } +Location::Location(const Point &p, uint32_t max_dist, uint32_t aspect) + : Parent(p, max_dist, GeoLocation::Aspect(aspect)) +{} + Location::Location(const Rectangle &rect, - const Point &point, uint32_t max_dist, uint32_t x_aspect) -{ - asciistream loc; - loc << "(2" // dimensionality - << "," << point.x - << "," << point.y - << "," << max_dist - << "," << "0" // table id. - << "," << "1" // rank multiplier. - << "," << "0" // rank only on distance. - << "," << x_aspect // x aspect. - << ")"; - loc << "[2," << rect.left - << "," << rect.top - << "," << rect.right - << "," << rect.bottom - << "]" ; - _location_string = loc.str(); + const Point &p, uint32_t max_dist, uint32_t aspect) + : Parent(convert(rect), p, max_dist, GeoLocation::Aspect(aspect)) +{} -} +Location::Location(const Rectangle &rect) + : Parent(convert(rect)) +{} -Location::Location(const Rectangle &rect) { - asciistream loc; - loc << "[2," << rect.left - << "," << rect.top - << "," << rect.right - << "," << rect.bottom - << "]" ; - _location_string = loc.str(); +bool +Location::operator==(const Location &other) const +{ + auto me = getOldFormatString(); + auto it = other.getOldFormatString(); + if (me == it) { + return true; + } else { + // dump 'me' and 'it' here if unit tests fail + return false; + } +} + +std::string +Location::getOldFormatString() const +{ + // we need to product what search::common::GeoLocationParser can parse + vespalib::asciistream buf; + if (has_point) { + buf << "(2" // dimensionality + << "," << point.x + << "," << point.y + << "," << radius + << "," << "0" // table id. + << "," << "1" // rank multiplier. + << "," << "0" // rank only on distance. + << "," << x_aspect.multiplier // aspect multiplier + << ")"; + } + if (bounding_box.active()) { + buf << "[2," << bounding_box.x.low + << "," << bounding_box.y.low + << "," << bounding_box.x.high + << "," << bounding_box.y.high + << "]" ; + } + return buf.str(); } vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc) { - return out << loc.getLocationString(); + return out << loc.getOldFormatString(); } } diff --git a/searchlib/src/vespa/searchlib/query/tree/location.h b/searchlib/src/vespa/searchlib/query/tree/location.h index e1826c7184a..6b8090f45e1 100644 --- a/searchlib/src/vespa/searchlib/query/tree/location.h +++ b/searchlib/src/vespa/searchlib/query/tree/location.h @@ -2,29 +2,26 @@ #pragma once -#include <vespa/vespalib/stllike/string.h> +#include <string> +#include <vespa/searchlib/common/geo_location_spec.h> +#include "point.h" +#include "rectangle.h" namespace vespalib { class asciistream; } namespace search::query { -struct Point; -struct Rectangle; - -class Location { - vespalib::string _location_string; +class Location : public search::common::GeoLocation { + using Parent = search::common::GeoLocation; public: - Location() : _location_string() {} + Location() {} + Location(const Parent &spec) : Parent(spec) {} + ~Location() {} Location(const Point &p, uint32_t dist, uint32_t x_asp); Location(const Rectangle &rect); Location(const Rectangle &rect, const Point &p, uint32_t dist, uint32_t x_asp); - Location(const vespalib::string &s) : _location_string(s) {} - bool operator==(const Location &other) const { - return _location_string == other._location_string; - } - const vespalib::string &getLocationString() const { - return _location_string; - } + bool operator==(const Location &other) const; + std::string getOldFormatString() const; }; vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc); diff --git a/searchlib/src/vespa/searchlib/query/tree/point.h b/searchlib/src/vespa/searchlib/query/tree/point.h index 89d0bc1db44..48700681158 100644 --- a/searchlib/src/vespa/searchlib/query/tree/point.h +++ b/searchlib/src/vespa/searchlib/query/tree/point.h @@ -3,18 +3,10 @@ #pragma once #include <cstdint> +#include <vespa/searchlib/common/geo_location.h> namespace search::query { -struct Point { - int64_t x; - int64_t y; - Point() : x(0), y(0) {} - Point(int64_t x_in, int64_t y_in) : x(x_in), y(y_in) {} -}; - -inline bool operator==(const Point &p1, const Point &p2) { - return p1.x == p2.x && p1.y == p2.y; -} +using Point = search::common::GeoLocation::Point; } diff --git a/searchlib/src/vespa/searchlib/query/tree/rectangle.h b/searchlib/src/vespa/searchlib/query/tree/rectangle.h index 97be9ddeb32..358e994aacd 100644 --- a/searchlib/src/vespa/searchlib/query/tree/rectangle.h +++ b/searchlib/src/vespa/searchlib/query/tree/rectangle.h @@ -5,20 +5,14 @@ namespace search::query { struct Rectangle { - int64_t left; - int64_t top; - int64_t right; - int64_t bottom; + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; Rectangle() : left(0), top(0), right(0), bottom(0) {} - Rectangle(int64_t l, int64_t t, int64_t r, int64_t b) + Rectangle(int32_t l, int32_t t, int32_t r, int32_t b) : left(l), top(t), right(r), bottom(b) {} }; -inline bool operator==(const Rectangle &r1, const Rectangle &r2) { - return r1.left == r2.left && r1.right == r2.right - && r1.top == r2.top && r1.bottom == r2.bottom; } - -} - diff --git a/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp b/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp index f33520d8b0e..82302e4ab48 100644 --- a/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp +++ b/searchlib/src/vespa/searchlib/query/tree/stackdumpcreator.cpp @@ -228,7 +228,7 @@ class QueryNodeConverter : public QueryVisitor { } void visit(LocationTerm &node) override { - createTerm(node, ParseItem::ITEM_LOCATION_TERM); + createTerm(node, ParseItem::ITEM_GEO_LOCATION_TERM); } void visit(PrefixTerm &node) override { diff --git a/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h b/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h index 898db9785f6..a7e00d41555 100644 --- a/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h +++ b/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h @@ -6,6 +6,7 @@ #include "querybuilder.h" #include "term.h" #include <vespa/searchlib/parsequery/stackdumpiterator.h> +#include <vespa/searchlib/common/geo_location_parser.h> #include <vespa/vespalib/objects/hexdump.h> namespace search::query { @@ -141,17 +142,15 @@ private: t = &builder.addStringTerm(term, view, id, weight); } else if (type == ParseItem::ITEM_SUFFIXTERM) { t = &builder.addSuffixTerm(term, view, id, weight); - } else if (type == ParseItem::ITEM_LOCATION_TERM) { - Location loc(term); + } else if (type == ParseItem::ITEM_GEO_LOCATION_TERM) { + search::common::GeoLocationParser parser; + parser.parseOldFormat(term); + Location loc(parser.getGeoLocation()); t = &builder.addLocationTerm(loc, view, id, weight); } else if (type == ParseItem::ITEM_NUMTERM) { if (term[0] == '[' || term[0] == '<' || term[0] == '>') { Range range(term); t = &builder.addRangeTerm(range, view, id, weight); - } else if (term[0] == '(') { - // TODO: handled above, should remove this block - Location loc(term); - t = &builder.addLocationTerm(loc, view, id, weight); } else { t = &builder.addNumberTerm(term, view, id, weight); } |