How to display "ALL" the nested documents in an object in separate rows from elasticsearch? - elasticsearch

I have a nested object in the following form:
{
"name": "Multi G. Enre",
"books": [
{
"name": "Guns and lasers",
"genre": "scifi",
"publisher": "orbit"
},
{
"name": "Dead in the night",
"genre": "thriller",
"publisher": "penguin"
}
]
}
I tried the following JSON query for the above document:
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"nested": {
"path": "books",
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"and": [
{
"term": {
"books.publisher": "penguin"
}
},
{
"term": {
"books.genre": "thriller"
}
}
]
}
}
}
}
}
}
}
}
So,I would like to see the second nested document i.e. "Dead in the night" as the result but, for anything I search only the first document i.e. "Guns and lasers" is displayed in the table in elasticsearch head plugin.
So, is there any way I can display the nested documents separately based on the search query and not just the first document?
I'm new to elasticsearch,so would appreciate any type of responses. THANKYOU!

You need to use inner_hits in your query.
Moreover, if you want to only retrieve the matching nested document and nothing else, you can add "_source":["books"] to your query and only the matching nested books will be returned, nothing else.
UPDATE
Sorry, I misunderstood your comment. You can add "_source": false and the top-level document will not be returned. Only the nested matching document.

Related

Make query in elasticsearch

I'm learning elastic for a new project.
I have a index with format:
{
"content_id": "bbbbbb",
"title": "content 2",
"data": [
{
"id": "xx",
"value": 3,
"tags": ["a","b","c"]
},
{
"id": "yy",
"value": 1,
"tags": ["e","d","c"]
}
]
}
How can i make a query to search contents that have at least one element in data that include tags "a" and "b" ?
thanks so much !!
How can i make query or re design my format data to easy make new query ?
Working with lists and nested documents in Elasticsearch is a bit tricky.
When creating the index, you need to specify the mapping for the nested documents. You can do this by adding a mapping for the data field.
PUT /my_index
{
"mappings": {
"doc": {
"properties": {
"data": {
"type": "nested"
}
}
}
}
}
If you have already created the index, you should delete it first, then create it again with the mapping.
Before deleting the index, you can reindex (copy) the data to a new index.
Now you can query the data field using the nested query:
GET /my_index/_search
{
"query": {
"nested": {
"path": "data",
"query": {
"terms": {
"data.tags": [
"j",
"b",
"c"
]
}
}
}
}
}
If the requirement is to get the document if at least one object in data contains a and b both, then you need to specify the nested mapping as suggested by #ChamRun.
But for getting the results having a and b both, you need to use the below query :
{
"query": {
"nested": {
"path": "data",
"query": {
"bool": {
"must": [
{
"term": {
"data.tags": "a"
}
},
{
"term": {
"data.tags": "b"
}
}
]
}
}
}
}
}

Elastic query combining should (boolean OR) with retrieval of nested documents

I have an Elastic index with nested documents. I am trying to retrieve multiple documents by ids along with their nested documents. Retrieving the documents themselves is simple enough with a Should query, but where and how would I include the nested doc query in this?
Boolean "Should" query:
GET myIndex/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"id": "123"
}
},
{
"term": {
"id": "456"
}
},
{
"term": {
"id": "789"
}
}
]
}
}
}
Query to retrieve nested docs:
"nested": {
"path": "myNestedDocs",
"query": {
"match_all": {}
}
It is not possible to add the nested query to each term query, because this gives a parsing exception: "[term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]"
Also, it is not possible to add the nested doc query on the same level as the term queries, because then it would be treated as just another OR clause and simply retrieve all docs from the index.
Any ideas? Thanks!
As per my understanding, you want to match any one id from list and retrive nested document. If my understanding correct then You need to combined both the query to must clause like below:
{
"query": {
"bool": {
"must": [
{
"terms": {
"id": [
"123",
"456",
"789"
]
}
},
{
"nested": {
"path": "myNestedDocs",
"query": {
"match_all": {}
}
}
}
]
}
}
}

how to make match query on array field more accurate

example:
here is a document:
{
"_source": {
"name": [
"beef soup",
"chicken rice"
]
}
}
it can be recalled by below query
{
"match": {
"name": {
"query": "soup chicken noodle",
"minimum_should_match": "67%"
}
}
}
but I only want it to be recalled by keyword hot beef soup or rice chicken hainan, is there any way except nested or span query to do this, thanks.
my es query is complex, anyone know how to rewrite it by span query
{
"query": {
"bool": {
"filter": [
...
],
"must": {
"dis_max": {
"queries": [
{
"match": {
"array_field_3": {
"boost": 2,
"minimum_should_match": "67%",
"query": "keyword aa bb"
}
}
},
......
{
"nested": {
"path": "path_1",
"query": {
"must": {
"match": {
"array_field_6": {
......
"query": "keyword aa bb"
}
}
}
}
}
}
}
],
"tie_breaker": 0.15
}
}
}
}
}
You can use match_phrase but it will only work for entire phrase. if you want to do only keyword match on each element of array then it is not possible without nested or span as mentioned in document.
Arrays of objects do not work as you would expect: you cannot query
each object independently of the other objects in the array. If you
need to be able to do this then you should use the nested data type
instead of the object data type.
When you get a document back from Elasticsearch, any arrays will be in the same order as when you indexed the document. The _source field that you get back contains exactly the same JSON document that you indexed.
However, arrays are indexed — made searchable — as multi-value fields, which are unordered. At search time you can’t refer to “the first element” or “the last element”.
Please try match_phrase query:
POST index1/_search
{
"query": {
"match_phrase": {
"text": {
"query": "chicken soup"
}
}
}
}

Multiple (AND) queries for a nested index structure in Elasticsearch

I have an index with the below mapping
{
"mappings": {
"xxxxx": {
"properties": {
"ID": {
"type": "text"
},
"pairs": {
"type": "nested"
},
"xxxxx": {
"type": "text"
}
}
}
}
}
the pairs field is essentially an array of objects - each object has a unique ID associated with it
What i'm trying to do is to get only one object from the pairs field for updates. To that extent , i've tried this
GET /sample/_search/?size=1000
{
"query": {
"bool": {
"must": [
{
"match": {
"ID": "2rXdCf5OM9g1ebPNFdZNqW"
}
},
{
"match": {
"pairs.id": "c1vNGnnQLuk"
}
}
]
}
},
"_source": "pairs"
}
but this just returns an empty object despite them being valid IDs. If i remove the pairs.id rule - i get the entire array of objects .
What do i need to add/edit to ensure that i can query via both IDS (original and nested)
Since pairs is of nested type, you need to use a nested query. Also you might probably want to leverage nested inner-hits as well:
GET /sample/_search/?size=1000
{
"query": {
"bool": {
"must": [
{
"match": {
"ID": "2rXdCf5OM9g1ebPNFdZNqW"
}
},
{
"nested": {
"path": "pairs",
"query": {
"match": {
"pairs.id": "c1vNGnnQLuk"
}
},
"inner_hits": {}
}
}
]
}
},
"_source": false
}

Source filtering for first of nested objects

I'm using source filtering on a query to just return a small set of information and within that information I want the first photo url of an object:
"query" : { ... },
"_source" : ["name", "photos.thumbnail_url"]
Of course this returns the thumbnail_url for all of the photos stored against each item.
Is there any way to get just the first nested photo's thumbnail_url using source filtering?
(I appreciate that one way to do it would be to index the first photo separately and just source filter to include that separate field but I'm asking whether it is possible without a separate field.)
(I've guessed a few approaches without luck: photos.0.thumbnail_url, photos[0].thumbnail_url, photos.first.thumbnail_url)
Just an attempt, as I don't know your mapping, with inner_hits:
{
"size": 5,
"_source": ["name"],
"query": {
"filtered": {
"query": {
"match": {
"name": "whatever"
}
},
"filter": {
"nested": {
"path": "photos",
"query": {
"match_all": {}
},
"inner_hits": {
"size": 1,
"_source": ["thumbnail_url"]
}
}
}
}
}
}
or use a script field:
"script_fields": {
"FIELD": {
"script": "urls=_source.photos.thumbnail_url;return urls[0]"
}
}
and I don't think it's possible to do this with source filtering.

Resources