Failing to search polygons that intersect with other polygons with elasticsearch - elasticsearch

In our app, ES holds objects with areas field, where areas field in a type of MultiPyligon. (basically, it's an array of polygons).
Now, we need to search for all the objects in which one of their polygons in at least partially falls within a given polygon (in our case it is the current viewport of the map).
The current query that we are experimenting with is the following:
$params = [
'index' => self::CrimeIndex,
'body' => [
'size' => 10000,
'query' => [
'bool' => [
'filter' => [
'geo_bounding_box' => [
'areas' => [
"top_left" => [
"lat" => $neLat,
"lon" => $neLng
],
"bottom_right" => [
"lat" => $swLat,
"lon" => $swLng
]
],
]
]
]
]
],
];
The problem is that this query gets all the polygons that touch the edges of the bounding box. (see picture). How can we get all the polygons that are at least partially within the bounding box?
Mappings are done as follows:
$params = [
'index' => CrimeService::CrimeIndex,
'body' => [
"mappings" => [
'properties' => [
'areas' => [
'type' => 'geo_shape'
]
],
],
],
];
$client->indices()->create($params);
Based on the docs, geo_shape can be MultiPolygon.
https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html
And here is the example of how it looks like populated:
GET crimes/_mapping/field/areas provides the following:
UPDATE - More Detailed Steps to reproduce
The dump of the collection/index is attached: https://www.dropbox.com/s/8inavsvcrnuozw1/dump-2021-12-29t21_54_04.639z.json.zip?dl=0
The query that is executed with elasticsearch-php is:
$params = [
'index' => 'crime',
'body' => [
'size' => 10000,
'query' => [
'bool' => [
'filter' => [
'geo_bounding_box' => [
'areas' => [
"top_left" => [
"lat" => $neLat,
"lon" => $neLng
],
"bottom_right" => [
"lat" => $swLat,
"lon" => $swLng
]
],
]
],
]
]
],
];
If we execute it with the parameters:
49.29366604017385,-123.00491857934166,49.19709977562233,-123.26617317321401
We get the following:
In case that the viewport is changed a bit, so the polygons touch the borders of viewport: 49.28031011582358,-122.92300503734472,49.18371770837152,-123.18425963121705,
we get the rest of the polygons:

Your query coordinates are wrong, instead of top_left + bottom_right, you have bottom_left + top_right (see image below)
I think that pretty much explains why you're seeing what you're seeing.

Related

Having issues searching polygons that intersect with other polygons with elasticsearch

In our app, ES holds objects with areas field, where areas field in a type of MultiPyligon. (basically, it's an array of polygons).
Now, we need to search for all the objects in which one of their polygons in at least partially falls within a given polygon (in our case it is the current viewport of the map).
The current query that we are experimenting with is the following:
$params = [
'index' => self::CrimeIndex,
'body' => [
'size' => 10000,
'query' => [
'bool' => [
'filter' => [
'geo_bounding_box' => [
'areas' => [
"top_left" => [
"lat" => $neLat,
"lon" => $neLng
],
"bottom_right" => [
"lat" => $swLat,
"lon" => $swLng
]
],
]
]
]
]
],
];
The problem is that this query gets all the polygons that touch the edges of the bounding box. (see picture).
How can we get all the polygons that are at least partially within the bounding box?

ElasticSearch 7 - combine filters

I use ES 7 and Laravel implementation, I want to combine a range and a term match, according to documentation, I did this :
$items = $client->search([
'index' => $instance->getSearchIndex(),
'type' => $instance->getSearchType(),
'body' => [
'size' => 50,
'query' => [
'bool' => [
'must' => [
'multi_match' => [
'fields' => config('elasticsearch.fields'),
'query' => $query,
],
],
'filter' => [
'bool' => [
'must' => [
'range' => [
'note' => [
'gte' => config('elasticsearch.note_minimum')
]
],
'term' => [
'type_video_id' => 5
],
],
],
],
]
],
],
]);
And got this error :
"parsing_exception","reason":"[range] malformed query, expected
[END_OBJECT] but found [FIELD_NAME]
I only found documentation and examples for ES 2 about combining queries, did something change ?
I want my query to match the fields, and be filtered according to filter.
Here is the right way to do this:
$items = $client->search([
'index' => $instance->getSearchIndex(),
'type' => $instance->getSearchType(),
'body' => [
'size' => 50,
'query' => [
'bool' => [
'must' => [
'multi_match' => [
'fields' => config('elasticsearch.fields'),
'query' => $query,
]
],
'filter' => [
[
'range' => [
'note' => [
'gte' => config('elasticsearch.note_minimum')
]
]
],
[
'term' => [
'type_video_id' => 5
]
]
]
]
]
]
]);
I don't have a way to test this, but I'm seeing a couple brackets where you need curlies. Also, don't you need you need $ before those "config"?
{
"query" => {
"bool" => {
"must" => [
{
"multi_match" => {
"query" => $query,
"fields" => $config('elasticsearch.fields')
}
}
],
"filter" => {
{
"range" => {
"note" => {
"gte" => $config('elasticsearch.note_minimum')
}
}
},
{
"term" => {
"type_video_id" => {
"value" => "5"
}
}
}
}
}
}
}
If this doesn't work, can you paste what the string looks like after your variables get rendered?

Elasticsearch syntax error with multi fields search

I watched Elasticsearch Do's, Don'ts and Pro-Tips by Itamar Syn Hershko
https://www.youtube.com/watch?v=c9O5_a50aOQ
I see multiple conditions in several fields in the following image:
https://imgur.com/a/17zAZ4w
I tried to make it in
my Laravel 5.7 app (with the elasticsearch/elasticsearch plugin) as seen in the following code:
$elasticQuery = [
"bool" => [
'must' => [
'multi_match' => [
'query' => $text,
'fields' => ['name^4', 'description']
],
],
"should" => [
'term' => [
"category_id" => 1,
]
]
]
];
but I got the error :
{"error":{"root_cause":[{"type":"parsing_exception","reason":"[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]","line":1,"col":130}],"type":"parsing_exception","reason":"[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]","line":1,"col":130},"status":400}
But when I use a simple condition:
$elasticQuery = [
'multi_match' => [
'query' => $text,
'fields' => ['name^4', 'description'],
],
];
I got a valid result:
[hits] => Array
(
[total] => 1
[max_score] => 7.4126062
[hits] => Array
(
[0] => Array
(
[_index] => select_vote
[_type] => vote
[_id] => 16
[_score] => 7.4126062
[_source] => Array
(
[id] => 16
[slug] => in-the-film-babe-what-type-of-animal-was-babe
[name] => In the film Babe, what type of animal was Babe?
[description] => Babe is a 1995 A...
[created_at] => 2018-11-10 09:14:15
[category_id] => 2
[category] => Array
(
[name] => Movie&Cartoons
[slug] => movie-cartoons
[created_at] => 2018-11-10 09:14:12
)
)
)
)
)
is this a valid format for multi-request?
MODIFIED BLOCK # 2:
Making some search I found work:
$elasticQuery = [
"bool" => [
'should' => [
[
"multi_match" => [
"query" => $text,
"type" => "cross_fields",
"fields" => [
"name^4",
"description"
]
]
],
[
'match' => [
'category_id' => [
'query' => 1,
]
]
],
[
'match' => [
'category_id' => [
'query' => 3,
]
]
],
]
]
];
when I need to make a search by text fields and the array of category (1 and 3) in the example above it works but looks like it works like an "OR" condition, but I need to make a restriction like "AND" using SQL terminology...
Which way is correct in order to make a restriction as like "AND"?
Thanks!
If you just change should to must it is not going to work because category_id cannot have two values at the same time (unless it's an array, but it's not).
You need to use the following query instead:
$elasticQuery = [
"bool" => [
'must' => [
[
"multi_match" => [
"query" => $text,
"type" => "cross_fields",
"fields" => [
"name^4",
"description"
]
]
],
],
'filter' => [
[
'terms' => [
'category_id' => [ 1, 3 ]
]
]
]
]
];

Calculate Average of an Array's indexes in ElasticSearch

I am trying to calculate average of the result set that is returning me locations from Elastic Search. Here is what i am trying.
'aggs' => [
"avg_location" => [
'avg' => [
'field' => 'location'
]
]
]
This returns error as location itself is an object/array that returns me [lat,long] of the point. I need to calculate average of lats and longs of all the points returned.
How can i do that? I tried quite a few things but none of them worked.
Here is the whole code.
$json = [
'query' => [
'bool' => [
'must_not' => [
'terms' => ['rarity' => []],
],
'must' => [
'range' => [
'disappearTime' => [
'gte' => 'now',
'lte' => 'now+1d'
]
]
],
'filter' => [
[
'geo_bounding_box' => [
'location' => [
'top_left' => [
'lat' => $northWestLat,
'lon' => $northWestLng
],
'bottom_right' => [
'lat' => $southEastLat,
'lon' => $southEastLng
]
]
]
]
]
]
],
'aggs' => [
"avg_location" => [
'avg' => [
'field' => 'location'
]
]
]
];
Thanks

How to order by date documents in aggregator with elasticsearch

I have this aggregators to deduplicate documents :
$searchParams['body'] = [
'aggs' => [
'dedup' => [
'terms' => [
'field' => 'source',
'size' => 50,
'order' => [
'max_hits' => "desc"
]
],
'aggs' => [
'dedup_hits' => [
'top_hits' => [
'size' => 1
]
],
'max_hits' => [
'max' => [
"script" => "doc.score"
]
]
]
]
]
];
This query order by document score. However, i want to order by _timestamp field. It's possible ? I have test with Date Histogram aggregator. But without success.

Resources