ElasticSearch and nested query - elasticsearch

Having a problem getting record with intersecting ('and') condition.
I have a doc:
{
"uuid": "1e2a0c06-af24-42e1-a31a-0f84233521de",
"subject": "subj",
"relations": [
{
"userUuid": "0f38e576-6b1f-4c1a-86a8-67a55a06d504",
"signed": false
},
{
"userUuid": "15979293-6b04-41a9-a6aa-bba99499496f",
"signed": true
}
]
}
Querying and expecting to get EMPTY result, cause conditions are met from different nested elements:
"bool": {
"must": [
{
"nested": {
"query": {
"term": {
"relations.userUuid": {
"value": "15979293-6b04-41a9-a6aa-bba99499496f",
"boost": 1.0
}
}
},
"path": "relations",
"ignore_unmapped": false,
"score_mode": "none",
"boost": 1.0
}
},
{
"nested": {
"query": {
"term": {
"relations.signed": {
"value": false,
"boost": 1.0
}
}
},
"path": "relations",
"ignore_unmapped": false,
"score_mode": "none",
"boost": 1.0
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
}
How to query that condition would be 'AND' within same nested object?

Updated the answer looking at your comment. You need to mention path in your nested document.
Scenario 1: If you want any of the nested documents to contain 5979293-6b04-41a9-a6aa-bba99499496f as userUuid and signed as true
POST <your_index_name>/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "relations", <---- Note this
"query": {
"term": {
"relations.userUuid": "15979293-6b04-41a9-a6aa-bba99499496f"
}
}
}
},
{
"nested": {
"path": "relations",
"query": {
"term": {
"relations.signed": false
}
}
}
}
]
}
}
}
This would return true if there are two nested documents, first nested doc containing the userUuid and second nested doc containing signed as false
Scenario 2: If you want both the fields to be present in a single nested document
POST <your_index_name>/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "relations", <---- Note this
"query": {
"bool": {
"must": [
{
"term": {
"relations.userUuid": "15979293-6b04-41a9-a6aa-bba99499496f"
}
},
{
"term": {
"relations.signed": false
}
}
]
}
}
}
}
]
}
}
}
In this scenario, a single nested document must contain both values.
Let me know if this helps!

Related

ElasticSearch - query documents where the nested field is empty array []

I am trying to filter by the empty arrays of the nested field.
I tried many different commands, even scripts, and flattened fields, but couldn't retrieve any results. Does anyone has experience with this, is it possible to be done in the ES? I also want to aggregate (count results) by the same empty array field value []
mapping
suitability:
type: "nested"
properties:
group:
type: "keyword"
code:
type: "keyword"
in the index, I have this nested field in every document
"suitability": [
{
"group": "RG309",
"code": 1
},
{
"group": "RG318",
"code": 1
},
{
"group": "RG355",
"code": 2
}
]
also some documents have an empty nested field
"suitability": []
query for empty suitability results ( DOESN'T WORK - always return total_hits: 0)
GET /_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"ignore_unmapped": [
true
],
"path": "suitability",
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "suitability"
}
}
]
}
}
}
}
]
}
},
"track_total_hits": true
}
query for not empty suitability ( THIS WORKS: returns all results )
{
"query": {
"bool": {
"must": [
{
"nested": {
"ignore_unmapped": [
true
],
"path": "suitability",
"query": {
"bool": {
"must": [
{
"terms": {
"suitability.rule_result": [
"1",
"2",
"3"
]
}
}
]
}
}
}
}
]
}
},
"track_total_hits": true
}

Sql query on elastic 6.8 does not work as expected. Array of nested objects are flattened same as of type object

Thanks for the answer in advance.
I am running a query
SELECT key
FROM records_index
WHERE
(product_nested_field.code = '1234' and product_nested_field.codeset = 'category1' OR product_nested_field.code = '444' and product_nested_field.codeset = 'category1')
AND (role_name IN ('user', 'admin'))
GROUP BY records_uuid
In records_index I have record with two products
[
{codeset: category1, code:444},
{codeset: category2, code:1234}
]
The problem is that query does find a specified record.
such behavior is expected for "type": "object" but why I am getting that result for product_nested_field of type nested?
when I translate SQL to JSON I am getting
{
"bool": {
"must": [
{
"bool": {
"must": [
{
"nested": {
"query": {
"term": {
"product_nested_field.codeset": {
"value": "category1"
}
}
}
}
}
]
}
},
{
"bool": {
"must": [
{
"bool": {
"should": [
{
"nested": {
"query": {
"term": {
"product_nested_field.code": {
"value": "1234"
}
}
}
}
},
{
"nested": {
"query": {
"term": {
"product_nested_field.code": {
"value": "444"
}
}
}
}
}
]
}
}
]
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
}
why elastic moves product_nested_field.codeset = 'category1' into separate nested query.

ElasticSearch should with nested and bool must_not exists

With the following mapping:
"categories": {
"type": "nested",
"properties": {
"category": {
"type": "integer"
},
"score": {
"type": "float"
}
}
},
I want to use the categories field to return documents that either:
have a score above a threshold in a given category, or
do not have the categories field
This is my query:
{
"query": {
"bool": {
"should": [
{
"nested": {
"path": "categories",
"query": {
"bool": {
"must": [
{
"terms": {
"categories.category": [
<id>
]
}
},
{
"range": {
"categories.score": {
"gte": 0.5
}
}
}
]
}
}
}
},
{
"bool": {
"must_not": [
{
"exists": {
"field": "categories"
}
}
]
}
}
],
"minimum_should_match": 1
}
}
}
It correctly returns documents both with and without the categories field, and orders the results so the ones I want are first, but it doesn't filter the results having score below the 0.5 threshold.
Great question.
That is because categories is not exactly a field from the elasticsearch point of view[a field on which inverted index is created and used for querying/searching] but categories.category and categories.score is.
As a result categories being not found in any document, which is actually true for all the documents, you observe the result what you see.
Modify the query to the below and you'd see your use-case working correctly.
POST <your_index_name>/_search
{
"query": {
"bool": {
"should": [
{
"nested": {
"path": "categories",
"query": {
"bool": {
"must": [
{
"terms": {
"categories.category": [
"100"
]
}
},
{
"range": {
"categories.score": {
"gte": 0.5
}
}
}
]
}
}
}
},
{
"bool": {
"must_not": [ <----- Note this
{
"nested": {
"path": "categories",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "categories.category"
}
},
{
"exists": {
"field": "categories.score"
}
}
]
}
}
}
}
]
}
}
],
"minimum_should_match": 1
}
}
}

Match multiple properties on the same nested document in ElasticSearch

I'm trying to accomplish what boils down to a boolean AND on nested documents in ElasticSearch. Let's say I have the following two documents.
{
"id": 1,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "anotheruser#domain.com"
}
]
},
{
"thirdLevels": [
{
"isActive": false,
"user": "user#domain.com"
}
]
}
]
}
{
"id": 2,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "user#domain.com"
}
]
}
]
}
In this case, I want to only match documents (in this case ID: 2) that have a nested document with both isActive: true AND user: user#domain.com.
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
}
}
}
]
}
}
}
However, what seems to be happening is that my query turns up both documents because the first document has one thirdLevel that has isActive: true and another thirdLevel that has the appropriate user.
Is there any way to enforce this strictly at query/filter time or do I have to do this in a script?
With nested-objects and nested-query, you have made most of the way.
All you have to do now is to add the inner hits flag and also use source filtering for move entire secondLevels documents out of the way:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
},
"inner_hits": {
"size": 100
}
}
}
]
}
}
}

Elasticsearch return exact match first then other matches

I have some PageDocuments which I would like to search based on the title, excluding PageDocuments with a path starting with some particular text. This field is analyzed. I would like some fuzziness to help users with spelling mistakes. I need to be able to do partial matches so some would match some text and this is some text.
If I use the following query I don't get an exact match back as the first result because of tf-idf
{
"size": 20,
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "myterm",
"fuzziness": 1
}
}
}
],
"must_not": [
{
"wildcard": {
"path": {
"value": "/test/*"
}
}
}
]
}
}
}
So then I added a not_analyzed version of the title field at title.not_analyzed and tried adding a function score to increase the weighting of an exact match using term.
{
"query": {
"function_score": {
"functions": [
{
"weight": 2,
"filter": {
"fquery": {
"query": {
"term": {
"title.not_analyzed": {
"value": "myterm"
}
}
}
}
}
}
],
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "myterm",
"fuzziness": 1
}
}
}
],
"must_not": [
{
"wildcard": {
"path": {
"value": "/path/*"
}
}
}
]
}
},
"boost_mode": "multiply"
}
}
}
But this gives me the same results. How can I get the exact matches returned first?
We found a solution to this by adding a combination of should and boost.
{
"size": 20,
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "myterm",
"fuzziness": 1
}
}
}
],
"must_not": [
{
"wildcard": {
"path": {
"value": "/path/*"
}
}
}
],
"should": [
{
"term": {
"title": {
"value": "myterm",
"boost": 10
}
}
}
]
}
}
}

Resources