-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add geo_bounding_box query for LatLonFields (#178)
* Add geo_bounding_box query for LatLonFields * Add GeoQueryable interface * Throw exception when field is not searchable
- Loading branch information
1 parent
7776ccb
commit 5d5f180
Showing
6 changed files
with
250 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/main/java/com/yelp/nrtsearch/server/luceneserver/field/properties/GeoQueryable.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
* Copyright 2020 Yelp Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.yelp.nrtsearch.server.luceneserver.field.properties; | ||
|
||
import com.yelp.nrtsearch.server.grpc.GeoBoundingBoxQuery; | ||
import org.apache.lucene.search.Query; | ||
|
||
/** | ||
* Trait interface for {@link com.yelp.nrtsearch.server.luceneserver.field.FieldDef} types that can | ||
* be queried by geo-related queries. | ||
*/ | ||
public interface GeoQueryable { | ||
/** | ||
* Build a geo bounding box query for this field type with the given configuration. | ||
* | ||
* @param geoBoundingBoxQuery geo bounding box query configuration | ||
* @return lucene box query | ||
*/ | ||
Query getGeoBoundingBoxQuery(GeoBoundingBoxQuery geoBoundingBoxQuery); | ||
} |
149 changes: 149 additions & 0 deletions
149
src/test/java/com/yelp/nrtsearch/server/luceneserver/field/LatLonFieldDefTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* Copyright 2020 Yelp Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.yelp.nrtsearch.server.luceneserver.field; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import com.google.type.LatLng; | ||
import com.yelp.nrtsearch.server.grpc.AddDocumentRequest; | ||
import com.yelp.nrtsearch.server.grpc.AddDocumentRequest.MultiValuedField; | ||
import com.yelp.nrtsearch.server.grpc.FieldDefRequest; | ||
import com.yelp.nrtsearch.server.grpc.GeoBoundingBoxQuery; | ||
import com.yelp.nrtsearch.server.grpc.Query; | ||
import com.yelp.nrtsearch.server.grpc.SearchRequest; | ||
import com.yelp.nrtsearch.server.grpc.SearchResponse; | ||
import com.yelp.nrtsearch.server.grpc.SearchResponse.Hit; | ||
import com.yelp.nrtsearch.server.luceneserver.ServerTestCase; | ||
import io.grpc.StatusRuntimeException; | ||
import io.grpc.testing.GrpcCleanupRule; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import org.junit.ClassRule; | ||
import org.junit.Test; | ||
|
||
public class LatLonFieldDefTest extends ServerTestCase { | ||
|
||
@ClassRule public static final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); | ||
|
||
protected List<String> getIndices() { | ||
return Collections.singletonList(DEFAULT_TEST_INDEX); | ||
} | ||
|
||
protected FieldDefRequest getIndexDef(String name) throws IOException { | ||
return getFieldsFromResourceFile("/field/registerFieldsLatLon.json"); | ||
} | ||
|
||
protected void initIndex(String name) throws Exception { | ||
List<AddDocumentRequest> docs = new ArrayList<>(); | ||
// Business in Fremont | ||
AddDocumentRequest fremontDocRequest = | ||
AddDocumentRequest.newBuilder() | ||
.setIndexName(name) | ||
.putFields("doc_id", MultiValuedField.newBuilder().addValue("1").build()) | ||
.putFields( | ||
"lat_lon_multi", | ||
MultiValuedField.newBuilder() | ||
.addValue("37.476220") | ||
.addValue("-121.904404") | ||
.addValue("37.506900") | ||
.addValue("-121.933121") | ||
.build()) | ||
.build(); | ||
// Business in SF | ||
AddDocumentRequest sfDocRequest = | ||
AddDocumentRequest.newBuilder() | ||
.setIndexName(name) | ||
.putFields("doc_id", MultiValuedField.newBuilder().addValue("2").build()) | ||
.putFields( | ||
"lat_lon_multi", | ||
MultiValuedField.newBuilder().addValue("37.781158").addValue("-122.414011").build()) | ||
.build(); | ||
docs.add(fremontDocRequest); | ||
docs.add(sfDocRequest); | ||
addDocuments(docs.stream()); | ||
} | ||
|
||
@Test | ||
public void testGeoBoxQuery() { | ||
GeoBoundingBoxQuery fremontGeoBoundingBoxQuery = | ||
GeoBoundingBoxQuery.newBuilder() | ||
.setField("lat_lon_multi") | ||
.setTopLeft( | ||
LatLng.newBuilder().setLatitude(37.589207).setLongitude(-122.019474).build()) | ||
.setBottomRight( | ||
LatLng.newBuilder().setLatitude(37.419254).setLongitude(-121.836704).build()) | ||
.build(); | ||
queryAndVerifyIds(fremontGeoBoundingBoxQuery, "1"); | ||
|
||
GeoBoundingBoxQuery sfGeoBoundingBoxQuery = | ||
GeoBoundingBoxQuery.newBuilder() | ||
.setField("lat_lon_multi") | ||
.setTopLeft( | ||
LatLng.newBuilder().setLatitude(37.793321).setLongitude(-122.430808).build()) | ||
.setBottomRight( | ||
LatLng.newBuilder().setLatitude(37.759250).setLongitude(-122.383569).build()) | ||
.build(); | ||
queryAndVerifyIds(sfGeoBoundingBoxQuery, "2"); | ||
|
||
// No results in Mountain View | ||
GeoBoundingBoxQuery mountainViewGeoBoxQuery = | ||
GeoBoundingBoxQuery.newBuilder() | ||
.setField("lat_lon_multi") | ||
.setTopLeft( | ||
LatLng.newBuilder().setLatitude(37.409778).setLongitude(-122.116884).build()) | ||
.setBottomRight( | ||
LatLng.newBuilder().setLatitude(37.346484).setLongitude(-121.984961).build()) | ||
.build(); | ||
queryAndVerifyIds(mountainViewGeoBoxQuery); | ||
} | ||
|
||
@Test(expected = StatusRuntimeException.class) | ||
public void testGeoBoxQueryNotSearchable() { | ||
GeoBoundingBoxQuery fremontGeoBoundingBoxQuery = | ||
GeoBoundingBoxQuery.newBuilder() | ||
.setField("lat_lon_not_searchable") | ||
.setTopLeft( | ||
LatLng.newBuilder().setLatitude(37.589207).setLongitude(-122.019474).build()) | ||
.setBottomRight( | ||
LatLng.newBuilder().setLatitude(37.419254).setLongitude(-121.836704).build()) | ||
.build(); | ||
queryAndVerifyIds(fremontGeoBoundingBoxQuery); | ||
} | ||
|
||
private void queryAndVerifyIds(GeoBoundingBoxQuery geoBoundingBoxQuery, String... expectedIds) { | ||
Query query = Query.newBuilder().setGeoBoundingBoxQuery(geoBoundingBoxQuery).build(); | ||
SearchResponse response = | ||
getGrpcServer() | ||
.getBlockingStub() | ||
.search( | ||
SearchRequest.newBuilder() | ||
.setIndexName(DEFAULT_TEST_INDEX) | ||
.setStartHit(0) | ||
.setTopHits(10) | ||
.setQuery(query) | ||
.addRetrieveFields("doc_id") | ||
.build()); | ||
List<String> idList = Arrays.asList(expectedIds); | ||
assertEquals(idList.size(), response.getHitsCount()); | ||
for (Hit hit : response.getHitsList()) { | ||
assertTrue(idList.contains(hit.getFieldsOrThrow("doc_id").getFieldValue(0).getTextValue())); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"indexName": "test_index", | ||
"field": [ | ||
{ | ||
"name": "doc_id", | ||
"type": "ATOM", | ||
"storeDocValues": true | ||
}, | ||
{ | ||
"name": "lat_lon_multi", | ||
"type": "LAT_LON", | ||
"multiValued": true, | ||
"storeDocValues": true, | ||
"sort": true, | ||
"search": true | ||
}, | ||
{ | ||
"name": "lat_lon_not_searchable", | ||
"type": "LAT_LON", | ||
"multiValued": true, | ||
"storeDocValues": true, | ||
"sort": true, | ||
"search": false | ||
} | ||
] | ||
} |