Elasticsearch: "must" query on nested fields - elasticsearch

How to do a "must" "match" query on multiple fields under the same nesting? Here's a reproducible ES index where the "user" field is defined as "nested" type.
PUT my_index
{
"mappings": {
"properties": {
"user": {
"type": "nested",
"properties": {
"firstname": {"type": "text"}
}
}
}
}
}
And here are 2 documents:
PUT my_index/_doc/1
{
"user" : [
{
"firstname" : "John"
},
{
"firstname" : "Alice"
}
]
}
PUT my_index/_doc/2
{
"user" : [
{
"firstname" : "Alice"
}
]
}
For this index, how can I query for documents where "John" AND "Alice" both exist? With the index defined above, I expect to get Document 1 but not Document 2. So far, I've tried the following code, but it's returning no hits:
GET my_index/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{"match": {"user.firstname": "John"}},
{"match": {"user.firstname": "Alice"}}
]
}
}
}
}
}

Below query is what is required.
POST my_index/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "user",
"query": {
"match": {
"user.firstname": "alice"
}
}
}
},
{
"nested": {
"path": "user",
"query": {
"match": {
"user.firstname": "john"
}
}
}
}
]
}
}
}
Notice how I've made use of two nested queries in a single must clause. That is because if you notice the documents that you have alice and john are both considered two different documents.
The query you have would work if your document structure is something like below:
POST my_index/_doc/3
{
"user" : [
{
"firstname" : ["Alice", "John"]
}
]
}
Try reading this (nested datatype) and this (nested query) link to understand more on how they work and from the second link, you can see the below info:
The nested query searches nested field objects as if they were indexed
as separate documents.
Hope that helps!

Related

ElasticSearch: Find record with multiple conditions on a list of sub-elements

I'm saving documents like this to ElasticSearch:
[
{
"text": "Sam works for Google.",
"entities": [
{
"text": "Sam",
"type": "PERSON"
},
{
"text": "Google",
"type": "ORGANIZATION"
}
]
}
]
It's essentially a sentence and entities that appear in that sentence. Now, I want to find any document that has entities of type "PERSON" AND "ORGANIZATION". I tried a boolean must query:
{
"bool": {
"must": [
{
"match": {
"entities.type": "PERSON"
}
},
{
"match": {
"entities.type": "ORGANIZATION"
}
}
]
}
}
... but that seems to try to look for entities that that are of both types, which obviously returns nothing. How do I need to formulate my query?
Thanks!
You should use below query as your original query dont have correct field name.
{
"query": {
"bool": {
"must": [
{
"match": {
"entities.type": "PERSON"
}
},
{
"match": {
"entities.type": "ORGANIZATION"
}
}
]
}
}
}

Nested Elasticsearch queries

I'm trying to create a nested query which would filter out some documents with specific terms. In this case I'm trying to filter out documents which have matching terms in user.first. Data example:
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Tim",
"last" : "White"
}
]
},
{
"group" : "fans",
"user" : [
{
"first" : "Jim",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "Black"
}
]
}
My query doesn't get the desired result as it returns me all records which are not filtered. I tried querying using:
"query": {
"bool": {
"must_not": [
{
"nested": {
"query": {
"terms": {
"user.first": [
"John",
"Thomas"
]
}
},
"path": "user"
}
}
]
}
}
I expect here to get documents which don't match with the filter. In this case it should return only the second document. What is the right way to do this?
After a lot of trial and error I've managed to find a solution for the problem. This is the query that filters out documents we don't need.
"query": {
"bool": {
"must_not": [
{
"bool": {
"filter": [
{
"nested": {
"query": {
"terms": {
"user.first": [
"John",
"Thomas"
]
}
},
"path": "user"
}
}
]
}
}
]
}
}

Querying Nested JSON based on 1 term value

I have indexed JSON like below format
JSON:
{"work":[{"organization":"abc", end:"present"},{"organization":"edf", end:"old"}]}
{"work":[{"organization":"edf", end:"present"},{"organization":"abc", end:"old"}]}
I want to query records where organization is "abc" and end is "present"
but below query is not working
work.0.organization: "abc" AND work.0.end:"present"
No records are matched
if I give query like below
work.organization: "abc" AND work.end:"present"
Both the records are matched. Whereas only the first record is what I want
The matched record should be only the below
{"work":[{"organization":"abc", end:"present"},{"organization":"edf", end:"old"}]}
You have to use nested_types. First map work as nested type in elastic using following mappings
PUT index_name_3
{
"mappings": {
"document_type" : {
"properties": {
"work" : {
"type": "nested",
"properties": {
"organization" : {
"type" : "text"
},
"end" : {
"type" : "text"
}
}
}
}
}
}
}
Use the following query to do nested filter match and innerhits
{
"query": {
"nested": {
"path": "work",
"inner_hits": {},
"query": {
"bool": {
"must": [{
"term": {
"work.organization": {
"value": "abc"
}
}
},
{
"term": {
"work.end": {
"value": "present"
}
}
}
]
}
}
}
}
}

Finding docs that do not contain a given user in all nested fields

I have the following mapping for a nested field called ratings:
"ratings" : {
"type" : "nested",
"properties" : {
"rating" : {
"type" : "double"
},
"user_id" : {
"type" : "long"
}
}
}
I'm attempting to find all records where a user_id does not exist in the nested field.
Here's what I have, but it's failing when there are multiple nested docs and any of the docs are not user_id 1.
{
"nested": {
"path": "ratings",
"query": {
"bool": { "must_not": [
{ "term": { "ratings.user_id": 1}}
]}}}}
If I'm understanding you correctly, and what you are trying to do is find documents for which NONE of the nested documents have a specific user_id, then this query seems to do what you want (assuming you want docs that have not been rated by user 2):
POST /test_index/_search
{
"query": {
"constant_score": {
"filter": {
"not": {
"filter": {
"nested": {
"path": "ratings",
"filter": {
"term": {
"ratings.user_id": 2
}
}
}
}
}
}
}
}
}
Here's the code I used to test it:
http://sense.qbox.io/gist/afd319e64403a7f995cbf1e9f40e5c5948729193

Elastic Search Nested Object mapping and Query for search

I am trying to use Elastic Search and I am stuck trying to query for the nested object.
Basically my object is of the following format
{
"name" : "Some Name",
"field2": [
{
"prop1": "val1",
"prop2": "val2"
},
{
"prop1": "val3",
"prop2":: "val4"
}
]
}
Mapping I used for the nested field is the following.
PUT /someval/posts/_mapping
{
"posts": {
"properties": {
"field2": {
"type": "nested"
}
}
}
}
Say now i insert elements for /field/posts/1 and /field/posts/2 etc. I have k values for field2.prop1 and i want a query which gets the posts sorted based on most match of field2.prop1 among the K values i have. What would be the appropriate query for that.
Also I tried a simple filter but even that doesnt seem to work right.
GET /someval/posts/_search
{
"query": {
"filtered": {
"query": {
"match_all": {}
}
},
"filter" : {
"nested" : {
"path" : "field2",
"filter" : {
"bool" : {
"must" : [
{
"term" : {"field2.prop1" : "val1"}
}
]
}
},
"_cache" : true
}
}
}
}
The above query should match atleast the first post. But it returns no match. Can anyone help to clarify whats wrong here ?
There was problem in your json structure, you used filtered query , but filter(object) was in different level than query.
Find the difference.
POST /someval/posts/_search
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"nested": {
"path": "field2",
"filter": {
"bool": {
"must": [
{
"term": {
"field2.prop1": "val1"
}
}
]
}
},
"_cache": true
}
}
}
}
}

Resources