From f7a501162914c4827b9ccb812ae09b394177cd97 Mon Sep 17 00:00:00 2001 From: Fabien CHOMETTON Date: Thu, 30 Nov 2017 10:21:08 +0100 Subject: [PATCH 1/4] add geodistance filter + doc --- README.md | 23 +++++++++++++ src/Filter/GeoDistanceFilter.php | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/Filter/GeoDistanceFilter.php diff --git a/README.md b/README.md index fa3bab4..6ec0a48 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,27 @@ const LIMIT = 10; $queryBuilder = QueryBuilder::createNew(0, 10, 0.3); ``` +#### GeoDistance query +Add property on the index : +```json +{ +//... + "_source": { + //... + "field_name" : { + "lat" : 40.12, + "lon" : -71.34 + } +//... + } +} +``` + +Add `Filter` in the `QueryBuilder` : +```php +$queryBuilder->addFilter(new GeoDistanceFilter('field_name', 'latitude_value', 'longitude_value', 'nb_kilometer')); +``` + > + **TODO** : Use a result formater + **TODO** : Filtering results @@ -132,6 +153,8 @@ parameters: analyzer: standard age: type: integer + location: + type: geo_point services: myapp.search.index: diff --git a/src/Filter/GeoDistanceFilter.php b/src/Filter/GeoDistanceFilter.php new file mode 100644 index 0000000..b713053 --- /dev/null +++ b/src/Filter/GeoDistanceFilter.php @@ -0,0 +1,59 @@ +property = $property; + $this->latitude = $latitude; + $this->longitude = $longitude; + $this->distance = $distance; + $this->combiningFactor = $combiningFactor; + } + + /** + * @return string + */ + public function getCombiningFactor(): string + { + return $this->combiningFactor; + } + + /** + * @inheritdoc + */ + public function formatForQuery(): array + { + return [ + 'geo_distance' => [ + 'distance' => sprintf('%dkm', $this->distance), + $this->property => [ + 'lat' => $this->latitude, + 'lon' => $this->longitude + ] + ] + ]; + } +} From 035bc8be1641cb7844b064acb8c0aac0fed69abb Mon Sep 17 00:00:00 2001 From: Fabien CHOMETTON Date: Thu, 30 Nov 2017 12:06:12 +0100 Subject: [PATCH 2/4] add behat test --- test/functional/bootstrap/FeatureContext.php | 33 ++++++++++++++++++++ test/functional/bootstrap/data/config.yml | 9 ++++++ test/functional/features/search.feature | 6 ++++ 3 files changed, 48 insertions(+) diff --git a/test/functional/bootstrap/FeatureContext.php b/test/functional/bootstrap/FeatureContext.php index b806684..079bfb1 100644 --- a/test/functional/bootstrap/FeatureContext.php +++ b/test/functional/bootstrap/FeatureContext.php @@ -176,6 +176,39 @@ public function iUpdateObjectOfTypeWithIdInIndexWithData($objectType, $id, $inde $objectIndexer->index(new IndexableObject($id, $newData), $objectType); } + /** + * @When I create geo objects of type "my_geo_type" to index :indexName + */ + public function iCreateObjectsOfTypeMyGeoTypeToIndex($indexName) + { + $objectIndexer = new ObjectIndexer($this->getIndex($indexName)); + + $cityArray = + [ + ['id ' => 1, 'city_name' => 'lyon', 'location' => ['lat' => '45.764043', 'lon' => '4.835658999999964' ]], + ['id ' => 2, 'city_name' => 'paris', 'location' => ['lat' => '48.85661400000001', 'lon' => '2.3522219000000177' ]], + ['id ' => 3, 'city_name' => 'mâcon', 'location' => ['lat' => '46.30688389999999', 'lon' => '4.828731000000062' ]] + ]; + + foreach ($cityArray as $cityRow) { + $indexableObject = new IndexableObject($cityRow['id'], $cityRow); + $objectIndexer->index($indexableObject, $objectType); + } + + sleep(1); + } + + /** + * @Given: I search cities with a coordinate :coordinate at :distance km + */ + public function iSearchCitiesWithCoordinateAtDistance($coordinate, $distance) + { + $arrayCoordinate = explode(',', $coordinate); + $this->queryBuilder = $this->queryBuilder ?? QueryBuilder::createNew(); + $queryBuilder->addFilter(new GeoDistanceFilter('location', $arrayCoordinate[0], $arrayCoordinate[1], $distance)); + } + + /** * @Then the object of type :objectType indexed in :indexName with id :id has data : */ diff --git a/test/functional/bootstrap/data/config.yml b/test/functional/bootstrap/data/config.yml index c08399f..ede16f9 100644 --- a/test/functional/bootstrap/data/config.yml +++ b/test/functional/bootstrap/data/config.yml @@ -19,3 +19,12 @@ mappings: search_analyzer: standard age: type: integer + my_geo_type: + _source : { enabled : true } + properties: + city_name: + type: string + analyzer: standard + search_analyzer: standard + location: + type: geo_point diff --git a/test/functional/features/search.feature b/test/functional/features/search.feature index 6219001..9b720a0 100644 --- a/test/functional/features/search.feature +++ b/test/functional/features/search.feature @@ -169,3 +169,9 @@ Feature: Search on index | age | 910 | filter | When I execute it on the index named "my_index" for type "my_type" Then the result should contain exactly ids "[2]" + + Scenario: Search City with geodistance + Given I create geo objects of type "my_geo_type" to index "my_index" + And I search cities with a coordinate "45.764043,4.835658999999964 " at "200" km + When I execute it on the index named "my_index" for type "my_geo_type" + Then the result should contain exactly ids "[1;3]" From 6da64603807a0f833d81c3dde52bf46810b7bd93 Mon Sep 17 00:00:00 2001 From: Fabien CHOMETTON Date: Thu, 30 Nov 2017 12:15:28 +0100 Subject: [PATCH 3/4] push dump --- test/functional/bootstrap/FeatureContext.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/functional/bootstrap/FeatureContext.php b/test/functional/bootstrap/FeatureContext.php index 079bfb1..c42bb87 100644 --- a/test/functional/bootstrap/FeatureContext.php +++ b/test/functional/bootstrap/FeatureContext.php @@ -190,9 +190,12 @@ public function iCreateObjectsOfTypeMyGeoTypeToIndex($indexName) ['id ' => 3, 'city_name' => 'mâcon', 'location' => ['lat' => '46.30688389999999', 'lon' => '4.828731000000062' ]] ]; + dump($cityArray); + foreach ($cityArray as $cityRow) { + dump($cityRow); $indexableObject = new IndexableObject($cityRow['id'], $cityRow); - $objectIndexer->index($indexableObject, $objectType); + $objectIndexer->index($indexableObject, 'my_geo_type'); } sleep(1); From 358de53d13a6008576403e34a9106066cd94be76 Mon Sep 17 00:00:00 2001 From: Fabien CHOMETTON Date: Thu, 30 Nov 2017 12:29:32 +0100 Subject: [PATCH 4/4] add correct test --- test/functional/bootstrap/FeatureContext.php | 16 +++++++--------- test/functional/features/search.feature | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/test/functional/bootstrap/FeatureContext.php b/test/functional/bootstrap/FeatureContext.php index c42bb87..eeebb39 100644 --- a/test/functional/bootstrap/FeatureContext.php +++ b/test/functional/bootstrap/FeatureContext.php @@ -9,6 +9,7 @@ use mageekguy\atoum\asserter\generator as AssertGenerator; use Novaway\ElasticsearchClient\Aggregation\Aggregation; use Novaway\ElasticsearchClient\Filter\ComparisonFilter; +use Novaway\ElasticsearchClient\Filter\GeoDistanceFilter; use Novaway\ElasticsearchClient\Filter\InArrayFilter; use Novaway\ElasticsearchClient\Filter\RangeFilter; use Novaway\ElasticsearchClient\Filter\TermFilter; @@ -185,15 +186,12 @@ public function iCreateObjectsOfTypeMyGeoTypeToIndex($indexName) $cityArray = [ - ['id ' => 1, 'city_name' => 'lyon', 'location' => ['lat' => '45.764043', 'lon' => '4.835658999999964' ]], - ['id ' => 2, 'city_name' => 'paris', 'location' => ['lat' => '48.85661400000001', 'lon' => '2.3522219000000177' ]], - ['id ' => 3, 'city_name' => 'mâcon', 'location' => ['lat' => '46.30688389999999', 'lon' => '4.828731000000062' ]] + ['id' => 1, 'city_name' => 'lyon', 'location' => ['lat' => '45.764043', 'lon' => '4.835658999999964' ]], + ['id' => 2, 'city_name' => 'paris', 'location' => ['lat' => '48.85661400000001', 'lon' => '2.3522219000000177' ]], + ['id' => 3, 'city_name' => 'mâcon', 'location' => ['lat' => '46.30688389999999', 'lon' => '4.828731000000062' ]] ]; - dump($cityArray); - foreach ($cityArray as $cityRow) { - dump($cityRow); $indexableObject = new IndexableObject($cityRow['id'], $cityRow); $objectIndexer->index($indexableObject, 'my_geo_type'); } @@ -202,13 +200,13 @@ public function iCreateObjectsOfTypeMyGeoTypeToIndex($indexName) } /** - * @Given: I search cities with a coordinate :coordinate at :distance km + * @Given I search cities with a coordinate :coordinate at :distance km */ - public function iSearchCitiesWithCoordinateAtDistance($coordinate, $distance) + public function iSearchCitiesWithACoordinateAtDistance($coordinate, $distance) { $arrayCoordinate = explode(',', $coordinate); $this->queryBuilder = $this->queryBuilder ?? QueryBuilder::createNew(); - $queryBuilder->addFilter(new GeoDistanceFilter('location', $arrayCoordinate[0], $arrayCoordinate[1], $distance)); + $this->queryBuilder->addFilter(new GeoDistanceFilter('location', $arrayCoordinate[0], $arrayCoordinate[1], $distance)); } diff --git a/test/functional/features/search.feature b/test/functional/features/search.feature index 9b720a0..0458436 100644 --- a/test/functional/features/search.feature +++ b/test/functional/features/search.feature @@ -172,6 +172,6 @@ Feature: Search on index Scenario: Search City with geodistance Given I create geo objects of type "my_geo_type" to index "my_index" - And I search cities with a coordinate "45.764043,4.835658999999964 " at "200" km + And I search cities with a coordinate "45.764043,4.835658999999964" at "200" km When I execute it on the index named "my_index" for type "my_geo_type" Then the result should contain exactly ids "[1;3]"