Elasticsearch 5.2 nested query for multi terms - elasticsearch

nested document look like this
{
"userid": "123",
"usertag": [
{
"tag": "A",
"logcreatetime": "2017-01-14"
},
{
"tag": "C",
"logcreatetime": "2017-01-17"
}
]
},
{
"userid": "456",
"usertag": [
{
"tag": "A",
"logcreatetime": "2017-01-12"
},
{
"tag": "B",
"logcreatetime": "2017-01-19"
}
]
},
.....
usertag object is nested mapping,
how to get user id by 2017-01-12 to 2017-01-19 , has tag A and B?
thanks
sorry for my english.

I'm assuming you've indexed your logcreatetime as Date field, so you can use the following query:
curl -XGET http://localhost:9200/my_users/_search -d '
{
"query": {
"bool": {
"must": [ {
"nested": {
"path": "usertag",
"query": {
"bool": {
"must": [
{ "match": { "usertag.tag": "A" }},
{ "range" : {
"usertag.logcreatetime" : {
"gte": "2017-01-12",
"lte": "2017-01-19"
}
}}
]
}
}
}
}, {
"nested": {
"path": "usertag",
"query": {
"bool": {
"must": [
{ "match": { "usertag.tag": "B" }},
{ "range" : {
"usertag.logcreatetime" : {
"gte": "2017-01-12",
"lte": "2017-01-19"
}
}}
]
}
}
}
}]
}
}
}'
The limitation of syntax is that you can look for particular child which both has particular tag AND its logcreatetime lies within given range. But in order to ensure you'll have two children you should combine two nested queries into 2 must clauses of top-level bool.

Related

How to apply combination of filters on array of objects in elasticsearch?

Hi Please help me to write a suitable query for my task, I have list of products with different categories and associated attribute and tags. Here is two documents for two categories along with associated attribute list. There could be multiple attributes, just showing one.
{
"category": "blouses",
"attributes": [
{
"attribute": "women-blouse-neckline",
"tag": "round-neck"
}
]
}
{
"category": "dresses",
"attributes": [
{
"attribute": "women-dress-neckline",
"tag": "v-neck"
}
]
}
Now I want to get list of products from both categories which are dresses and blouses, but along with that a specific case at attribute level is :
Fetch all the products from dresses where attribute is women-dress-neckline and tag is v-neck along with all the products from blouses where attribute is women-blouse-neckline and tag is round-neck.
Thanks.
To query on each key of "attributes", you need to define "attributes" to be of the nested type, and then use a combination of bool/must and nested query
Adding a working example with index mapping, search query and search result
Index Mapping:
{
"mappings": {
"properties": {
"attributes": {
"type": "nested"
}
}
}
}
Search Query:
{
"query": {
"bool": {
"must": [
{
"match": {
"category": "dresses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-dress-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "v-neck"
}
}
]
}
}
}
}
]
}
}
}
Search Result:
"hits": [
{
"_index": "69611494",
"_type": "_doc",
"_id": "2",
"_score": 2.0794413,
"_source": {
"category": "dresses",
"attributes": [
{
"attribute": "women-dress-neckline",
"tag": "v-neck"
}
]
}
}
]
Update 1:
You can combine two nested queries as shown below
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"match": {
"category": "dresses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-dress-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "v-neck"
}
}
]
}
}
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"category": "blouses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-blouse-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "round-neck"
}
}
]
}
}
}
}
]
}
}
]
}
}
}

Search for documents matching all terms in a nested array Elasticsearch

I am learning to use Elasticsearch as a basic recommender engine.
My elasticsearch document contains records with nested entities as follows
PUT recs/user/1
{
"name" : "Brad Pitt",
"movies_liked": [
{
"name": "Forrest Gump",
"score": 1
},
{
"name": "Terminator",
"score": 4
},
{
"name": "Rambo",
"score": 4
},
{
"name": "Rocky",
"score": 4
},
{
"name": "Good Will Hunting",
"score": 2
}
]
}
PUT recs/user/2
{
"name" : "Tom Cruise",
"movies_liked": [
{
"name": "Forrest Gump",
"score": 2
},
{
"name": "Terminator",
"score": 1
},
{
"name": "Rocky IV",
"score": 1
},
{
"name": "Rocky",
"score": 1
},
{
"name": "Rocky II",
"score": 1
},
{
"name": "Predator",
"score": 4
}
]
}
I would like to search for users who specifically like "Forrest Gump","Terminator" and "Rambo".
I have used a nested query which currently looks like this
POST recs/user/_search
{
"query": {
"nested": {
"path": "movies_liked",
"query": {
"terms": {
"movies_liked.name": ["Forrest Gump","Terminator","Rambo"]
}
}
}
}
}
However when I execute this search, I expected to see only the first record which has all the required terms, but in the results I am getting both the records. In the second record the user clearly does not have "Rambo" in his liked list. I understand that this query is doing an "OR" operation with the given terms, How do I tweak this query to do an "AND" operation so that only the records having all the terms get matched?
How do I tweak this query to do an "AND" operation so that only the records having all the terms get matched?
By using a bool query:
POST recs/user/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "movies_liked",
"query": {
"bool": {
"must": [
{
"terms": {
"movies_liked.name": [
"Forrest Gump"
]
}
}
]
}
}
}
},
{
"nested": {
"path": "movies_liked",
"query": {
"bool": {
"must": [
{
"terms": {
"movies_liked.name": [
"Terminator"
]
}
}
]
}
}
}
},
{
"nested": {
"path": "movies_liked",
"query": {
"bool": {
"must": [
{
"terms": {
"movies_liked.name": [
"Rambo"
]
}
}
]
}
}
}
}
]
}
}
}
Note that bool wraps around several nested queries, not the other way around. It is important because the scope of a nested query is the nested document, because it basically a hidden separate object.
Hope that helps!

ElasticSearch How to AND a nested query

I am trying to figure out how to AND my Elastic Search query. I've tried a few different variations but I am always hitting a parser error.
What I have is a structure like this:
{
"title": "my title",
"details": [
{ "name": "one", "value": 100 },
{ "name": "two", "value": 21 }
]
}
I have defined details as a nested type in my mappings. What I'm trying to achieve is a query where it matches a part of the title and it matches various details by the detail's name and value.
I have the following query which gets me nearly there but I haven't been able to figure out how to AND the details. As an example I'd like to find anything that has:
detail of one with value less than or equal to 100
AND detail of two with value less than or equal to 25
The following query only allows me to search by one detail name/value:
"query" : {
"bool": {
"must": [
{ "match": {"title": {"query": titleQuery, "operator": "and" } } },
{
"nested": {
"path": "details",
"query": {
"bool": {
"must": [
{ "match": {"details.name" : "one"} },
{ "range": {"details.value" : { "lte": 100 } } }
]
}
}
} // nested
}
] // must
}
}
As a second question, would it be better to query the title and then move the nested part of the query into a filter?
You were so close! Just add another "nested" clause in your outer "must":
POST /test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "title",
"operator": "and"
}
}
},
{
"nested": {
"path": "details",
"query": {
"bool": {
"must": [
{"match": {"details.name": "one" } },
{ "range": { "details.value": { "lte": 100 } } }
]
}
}
}
},
{
"nested": {
"path": "details",
"query": {
"bool": {
"must": [
{"match": {"details.name": "two" } },
{ "range": { "details.value": { "lte": 25 } } }
]
}
}
}
}
]
}
}
}
Here is some code I used to test it:
http://sense.qbox.io/gist/1fc30d49a810d22e85fa68d781114c2865a7c92e
EDIT: Oh, the answer to your second question is "yes", though if you're using 2.0 things have changed a little.

Elastic search DSL Syntax equivalence for SQL statement

I'm trying to replicate the below query logic in an elastic search query but something's not right.
Basically the query below returns one doc. I'd like either the first condition to be applied: "name": "iphone" OR the more complex second one which is: (username = 'gogadget' AND status_type = '1' AND created_time between 4532564 AND 64323238). Note that the nested bool must inside the should would take care of the more complex condition. I should still see 1 doc if I change the outside match of "name": "iphone" to be changed to "name": "wrong value". But I get nothing when I do that. I'm not sure where this is wrong.
The SQL Query is here below.
SELECT * from data_points
WHERE name = 'iphone'
OR
(username = 'gogadget' AND status_type = '1' AND created_time between 4532564 AND 64323238)
{
"size": 30,
"query": {
"bool": {
"must": [
{
"bool": {
"minimum_should_match": "1",
"should": [
{
"bool": {
"must": [
{
"match": {
"username": "gogadget"
}
},
{
"terms": {
"status_type": [
"3",
"4"
]
}
},
{
"range": {
"created_time": {
"gte": 20140712,
"lte": 1405134711
}
}
}
]
}
}
],
"must": [],
"must_not": []
}
},
{
"match": {
"name": "iphone"
}
}
]
}
}
}
should query will match the query and return.
You don't need use must to aggregate your OR query.
The query should like:
{
"query": {
"bool": {
"should": [{
"bool": {
"must": [{
"match": {
"username": "gogadget"
}
}, {
"terms": {
"status_type": [
"3",
"4"
]
}
}, {
"range": {
"created_time": {
"gte": 20140712,
"lte": 1405134711
}
}
}]
}
}, {
"match": {
"name": "iphone"
}
}]
}
}
}

Elasticsearch AND Parens

I'm attempting to do the following with the query dsl but I'll express it as SQL:
(matrices.matrix = 'Matrix1' AND matrices.count = 1) AND (matrices.matrix = 'Matrix2' AND matrices.count >= 0)
So, I need to get docs that have both of these nested docs with these values.
This is the nested document it sits on the _source level
"matrices": [
{
"terms": [],
"count": 0,
"matrix": "none"
},
{
"terms": [
"greater"
],
"count": 1,
"matrix": "Matrix1"
}
]
And here is the mapping for the sub-doc:
"matrices": {
"type": "nested",
"include_in_parent": true,
"properties": {
"count": {
"type": "long"
},
"matrix": {
"type": "string"
},
"terms": {
"type": "string"
}
}
}
So, I need to generate a query that will allow me to get docs that match both (matrix = 'none' && count=0) && (matrix = 'Matrix' && count = 1)
Thanks,
So basically you want to retrieve documents that MUST contain two nested documents with the following criteria:
one nested document with matrices.count=0 AND matrices.matrix=none
another nested document with matrices.count=1 AND matrices.matrix=Matrix
Then with the mapping you have, you can achieve that result using the following query. We use bool/must for two nested queries which in turn match the criteria each of the nested documents that must be retrieved.
curl -XPOST localhost:9200/_search -d '{
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"nested": {
"path": "matrices",
"query": {
"bool": {
"must": [
{
"term": {
"matrices.count": 0
}
},
{
"term": {
"matrices.matrix": "none"
}
}
]
}
}
}
},
{
"nested": {
"path": "matrices",
"query": {
"bool": {
"must": [
{
"term": {
"matrices.count": 1
}
},
{
"term": {
"matrices.matrix": "matrix"
}
}
]
}
}
}
}
]
}
}
}
}
}

Resources