Find documents with at least one null value in array of objects - elasticsearch

Our data structure looks as follows
{
"foo": "bar",
"baz": [
{
"qux": true
},
{
"qux": null
},
{
"qux": false
}
]
}
In other documents, the number of items in the baz array might vary.
We're looking to find documents that have at least one null value for qux in the baz array.
We have tried:
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "baz.qux"
}
}
}
}
}
However, this will not return documents that have e.g. one true and one null value for qux in the baz array.
Any help would be greatly appreciated!

You can simply check whether the field having null or not using the missing query.
{
"query" : {
"constant_score" : {
"filter": {
"missing" : { "field" : "baz.qux" }
}
}
}
}
You can check the elastic document as well on below link:
Documentation: Is null Query

You can achieve this with a nested mapping and nested query.
Mapping:
{
"properties": {
"foo": {
"type": "text"
},
"baz": {
"type": "nested",
"properties": {
"qux": {
"type": "boolean"
}
}
}
}
}
Query:
{
"query": {
"nested": {
"path": "baz",
"query": {
"bool": {
"must_not": {
"exists": {
"field": "baz.qux"
}
}
}
}
}
}
}

Related

Doing aggregation on object in Elasticsearch

I would like to do an aggregation on one of the object type but I couldn't make it work. I created a mapping from dynamic_templates because my object is dictionary and the key is list of constants. Here is my object, mapping and aggregate query.. even I can't access indexed field by must->exists query.
Document
{
"property":{
"innerProperty":{
"constantKey":{
"someArrays":[
{
"id":"12345"
}
]
}
}
}
}
Mapping
{
"dynamic_templates": [
{
"property_map": {
"path_match": "property.innerProperty.*",
"mapping": {
"type": "object",
"dynamic": false
}
}
}
]
}
Mapping result after adding a document
"property": {
"properties": {
"innerProperty": {
"properties": {
"constantKey": {
"type": "object",
"dynamic": "false"
}
}
}
}
}
Aggregation
GET /index/_search
{
"query": {
"bool": {
"must": {
"exists": {
"field": "property.innerProperty.constantKey"
}
}
}
}
}
Query
GET /index/_search
{
"aggs": {
"property-agg": {
"terms": {
"field": "property.innerProperty.constantKey"
}
}
},
"size": 0
}
Both of aren't working. I would like to do an aggregation by constantKey so that I would get the correct document count to facets make it work.

Can you reference other queries in Elasticsearch percolator?

can percolator queries reference other stored query docs in a percolator index? For example, given I have the following Boolean query, with _id=1, already indexed in the percolator:
{
"query": {
"bool": {
"must": [
{ "term": { "tag": "wow" } }
]
}
}
}
Could I have another query, with _id=2, indexed (note that I'm making up the _percolator_ref_id terms query key):
{
"query": {
"bool": {
"should": [
{ "term": { "tag": "elasticsearch" } },
{ "terms" : { "_percolator_ref_id": [1] } }
]
}
}
}
If I percolated the following document:
{ "tag": "wow" }
I would expect both _id=1 and _id=2 queries to match. Does some functionality like _percolator_ref_id exist?
Thanks!
Edit: To clarify, I do not know beforehand how many query references appear in a given query (e.g., the _id=2 query could reference 10 other queries potentially).
You can do something like below
2 queries are registered in below index
PUT myindex
{
"mappings": {
"properties": {
"query1": {
"type": "percolator"
},
"query": {
"type": "percolator"
},
"field": {
"type": "text"
}
}
}
}
You can use bool and must/should to combine different queries
GET /myindex/_search
{
"query": {
"bool": {
"must": [
{
"percolate": {
"field": "query",
"document": {
"field": "fox jumps over the lazy dog"
}
}
},
{
"percolate": {
"field": "query1",
"document": {
"field": "fox jumps over the lazy dog"
}
}
}
]
}
}
}

Elastic Search query for an AND condition on two properties of a nested object

I have the post_filter as below, Where I am trying to filter records where the school name is HILL SCHOOL AND containing a nested child object with name JOY AND section A.
school is present in the parent object, Which is holding children list of nested objects.
All of the above are AND conditions.
But the query doesn't seem to work. Any idea why ? And is there a way to combine the two nested queries?
GET /test_school/_search
{
"query": {
"match_all": {}
},
"post_filter": {
"bool": {
"must_not": [
{
"bool": {
"must": [
{
"term": {
"schoolname": {
"value": "HILL SCHOOL"
}
}
},
{
"nested": {
"path": "children",
"query": {
"bool": {
"must": [
{
"match": {
"name": "JACK"
}
}
]
}
}
}
},
{
"term": {
"children.section": {
"value": "A"
}
}
}
]
}
}
]
}
}
}
The schema is as below:
PUT /test_school
{
"mappings": {
"_doc": {
"properties": {
"schoolname": {
"type": "keyword"
},
"children": {
"type": "nested",
"properties": {
"name": {
"type": "keyword",
"index": true
},
"section": {
"type": "keyword",
"index": true
}
}
}
}
}
}
}
Sample data as below:
POST /test_school/_doc
{
"schoolname":"HILL SCHOOL",
"children":{
"name":"JOY",
"section":"A"
}
}
second record
POST /test_school/_doc
{
"schoolname":"HILL SCHOOL",
"children":{
"name":"JACK",
"section":"B"
}
}
https://stackoverflow.com/a/17543151/183217 suggests special mapping is needed to work with nested objects. You appear to be falling foul of the "cross object matching" problem.

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"
}
}
}
]
}
}
}
}
}

Find empty strings in elasticsearch

I'm trying to _search documents that has some specific value in the field.
{
"query": {
"bool": {
"must": [
{"field": {"advs.status": "warn"}}
]
}
}
}
That works find. But when I'm trying to find documents that has empty string in that field, I get this error:
ParseException[Cannot parse '' ...
and then - long list of what was expected instead of empty string.
I try this query:
{
"query": {
"bool": {
"must": [
{"term": {"advs.status": ""}}
]
}
}
}
It doesn't fails but finds nothing. It works for non empty strings instead. How am I supposed to do this?
My mapping for this type looks exactly like this:
{
"reports": {
"dynamic": "false",
"_ttl": {
"enabled": true,
"default": 7776000000
},
"properties": {
"#fields": {
"dynamic": "true",
"properties": {
"upstream_status": {
"type": "string"
}
}
},
"advs": {
"properties": {
"status": {
"type": "string",
"store": "yes"
}
}
},
"advs.status": {
"type": "string",
"store": "yes"
}
}
}
}
Or another way to do the same thing more efficiently is to use the exists filter:
"exists" : {
"field" : "advs.status"
}
Both are valid, but this one is better :)
You can try this temporary solution which works but isn't optimal - https://github.com/elastic/elasticsearch/issues/7515
PUT t/t/1
{
"textContent": ""
}
PUT t/t/2
{
"textContent": "foo"
}
GET t/t/_search
{
"query": {
"bool": {
"must": [
{
"exists": {
"field": "textContent"
}
}
],
"must_not": [
{
"wildcard": {
"textContent": "*"
}
}
]
}
}
}
Try using must_not with missing in your bool:
"must_not":{
"missing":{
"field":"advs.status",
"existence":true,
"null_value":true
}
}
If tou want to search for fields containing an empty string, either you change your mapping to set not_analyzed to this particular field or you can use a script filter:
"filter": {
"script": {
"script": "_source.advs.status.length() == 0"
}
}
I generally use a filter if the field is not analyzed. Here is snippet:
{
"filtered": {
"filter": {
"term": {
"field": ""
}
}
}
},
the "missing" does work only for null values or not being there at all. Matching empty string was already answered here: https://stackoverflow.com/a/25562877/155708

Resources