Elasticsearch 2.3 has_child with must_not.exists query - elasticsearch

I am trying to construct a query in which children of a parent are filtered based on a country code in an array. If the child has no countries field I still want to return the result.
I have two working queries:
{
"query": {
"bool": {
"should": {
"has_child": {
"inner_hits": {},
"type": "service",
"score_mode": "sum",
"query": {
"bool": {
"filter": [
{
"term": {
"countries": "AF"
}
}
]
}
}
}
}
}
}
}
duly returns an array of results where 'AF' is in the countries array and:
{
"query":
{
"bool": {
"should": {
"has_child": {
"inner_hits": {},
"type": "service",
"score_mode": "sum",
"query": {
"bool": {
"must_not": {
"exists": {
"field": "countries"
}
}
}
}
}
}
}
}
}
returns the results I want where the child has no countries field.
What I can't figure out is how to combine those two queries to get one combined set of results. That is to say I want to 'OR' the two sets.

Haven't actually tested this, it's a blind suggestion:
{
"query": {
"bool": {
"should": {
"has_child": {
"inner_hits": {},
"type": "service",
"score_mode": "sum",
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"exists": {
"field": "countries"
}
},
{
"term": {
"countries": "AF"
}
}
]
}
},
{
"missing": {
"field": "countries"
}
}
]
}
},
{
"term": {
"whatever": "blabla"
}
}
]
}
}
}
}
}
}
}

Related

ElasticSearch - combining search queries not working

I would like to have an intersection of 2 queries
I got 3 documents in the index:
"_id": "68c220aa-ea51-4f84-b880-29af3302cae9",
"_id": "b6c1c3c5-e959-480f-a145-f5598fafea66",
"_id": "2d30de72-0a2b-465c-8770-970ad9760d47",
Query1:
{
"from": 0,
"query": {
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asReference": {
"query": "8670ff39-6a0d-4ae8-e217-08d88efd4771"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "f51ca670-4223-4ea2-8007-d111dd38a14f"
}
}
}
]
}
}
]
}
}
}
},
"size": 10,
"sort": [
{
"modified": {
"order": "asc"
}
},
{
"created": {
"order": "asc"
}
}
]
}
returns all 3 documents as it should
"_id": "68c220aa-ea51-4f84-b880-29af3302cae9",
"_id": "b6c1c3c5-e959-480f-a145-f5598fafea66",
"_id": "2d30de72-0a2b-465c-8770-970ad9760d47",
Then I do query2:
{
"from": 0,
"query": {
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asShortString": {
"query": "RA-005"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "7ff3dbc1-3586-4475-9162-5430bb06c6d0"
}
}
}
]
}
}
]
}
}
}
},
"size": 10,
"sort": [
{
"modified": {
"order": "asc"
}
},
{
"created": {
"order": "asc"
}
}
]
}
returns 1 document:
"_id": "b6c1c3c5-e959-480f-a145-f5598fafea66"
But when I combine the queries to:
{
"from": 0,
"query": {
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asReference": {
"query": "8670ff39-6a0d-4ae8-e217-08d88efd4771"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "f51ca670-4223-4ea2-8007-d111dd38a14f"
}
}
}
]
}
},
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asShortString": {
"query": "RA-005"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "7ff3dbc1-3586-4475-9162-5430bb06c6d0"
}
}
}
]
}
}
]
}
}
}
},
"size": 10,
"sort": [
{
"modified": {
"order": "asc"
}
},
{
"created": {
"order": "asc"
}
}
]
}
Here I do not get any documents
So the subqueries are working but combined it does not work (it produces 0 results)
What am I missing here?
Due to the way nested documents and queries work, you need to have two separate nested queries in your bool/must query, because each will/might match a different nested document of the same parent document:
{
"from": 0,
"query": {
"bool": {
"must": [
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asReference": {
"query": "8670ff39-6a0d-4ae8-e217-08d88efd4771"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "f51ca670-4223-4ea2-8007-d111dd38a14f"
}
}
}
]
}
}
]
}
}
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"match_phrase": {
"attributes.asShortString": {
"query": "RA-005"
}
}
},
{
"match_phrase": {
"attributes.attributeId": {
"query": "7ff3dbc1-3586-4475-9162-5430bb06c6d0"
}
}
}
]
}
}
]
}
}
}
}
]
}
},
"size": 10,
"sort": [
{
"modified": {
"order": "asc"
}
},
{
"created": {
"order": "asc"
}
}
]
}

Weighted search on one field and a normal search on other field

I am trying to perform a search by matching the search query to either the tag or the name of the doc, I also have a filter on the top, so I do have to use must.
Here is what I have been trying,
{
"query": {
"bool": {
"filter": {
"term": {
"type.primary": "audio"
}
},
"must": [
{
"nested": {
"path": "tags",
"score_mode": "sum",
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"match": {
"tags.tag": "big"
}
}
]
}
},
"field_value_factor": {
"field": "tags.weight"
},
"boost_mode": "multiply",
"boost": 10
}
}
}
},
{
"bool": {
"must": [
{
"multi_match": {
"query": "big",
"fields": [
"name"
],
"type": "phrase_prefix"
}
}
]
}
}
]
}
}
}
This just results in empty.
If I use should instead of must the query works fine, but it gives me all results with the filter of type.primary: audio.
I am pretty sure there is some other way to search for the name field. Thanks.
You're almost there! In your must, you declare that both tags and name has to hit. Try the following:
GET /_search
{
"query": {
"bool": {
"filter": {
"term": {
"type.primary": "audio"
}
},
"must": [
{
"bool": {
"should": [
{
"nested": {
"path": "tags",
"score_mode": "sum",
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"match": {
"tags.tag": "big"
}
}
]
}
},
"field_value_factor": {
"field": "tags.weight"
},
"boost_mode": "multiply",
"boost": 10
}
}
}
},
{
"multi_match": {
"query": "big",
"fields": [
"name"
],
"type": "phrase_prefix"
}
}
]
}
}
]
}
}
}

Is it possible to do nested sort with a conditional query on a sort element

we have following structure in an index - following is only a partial and doc relevant for this question.
"instance" : {
"id" : 1,
{"instFields": [
{
"sourceFieldId": 2684,
"fieldValue": "false",
"fieldBoolean": false
},
{
"sourceFieldId": 1736,
"fieldValue": "DODGE",
"fieldString": "DODGE"
},
{
"sourceFieldId": 1560,
"fieldValue": "GRAY",
"fieldString": "GRAY"
},
{
"sourceFieldId": 1558,
"fieldValue": "CHALLENGER",
"fieldString": "CHALLENGER"
},
{
"sourceFieldId": 1556,
"fieldValue": "2010",
"fieldDouble": 2010
}
]
}
first user query is give me all instances where sourceFieldId=1736 - this returns all the DODGE instances[] - all this is working fine with an appripriate Elastic Search query. now when user is seeing all DODGE records - user wants to sort by any of those sourceFieldIds for e.g. say user is wanting to sort results by - color - sourceFieldId=1560.
say we have following sort query
{
"query": {
"bool": {
"filter": {
"bool": {
"must": [
{
"nested": {
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"instance.dataSourceId": "196"
}
},
{
"term": {
"instance.dsTypeId": "5"
}
},
{
"nested": {
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"instance.instFields.sourceFieldId": "1558"
}
},
{
"term": {
"instance.instFields.fieldString.raw": "challenger"
}
}
]
}
}
}
},
"path": "instance.instFields"
}
}
]
}
}
}
},
"path": "instance",
"inner_hits": {
"name": "inner_data"
}
}
},
{
"nested": {
"query": {
"bool": {
"should": {
"bool": {
"must": [
{
"match": {
"instance.entitlements.roleId": {
"query": "1",
"type": "boolean"
}
}
},
{
"match": {
"instance.entitlements.read": {
"query": "true",
"type": "boolean"
}
}
}
]
}
}
}
},
"path": "instance.entitlements"
}
}
]
}
}
}
},
"sort": {
"instance.instFields.fieldString.raw": {
"order": "asc",
"nested_path": "instance.instFields",
"nested_filter": {
"bool": {
"filter": {
"bool": {
"must": [
{
"nested": {
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"instance.dataSourceId": "196"
}
},
{
"term": {
"instance.dsTypeId": "5"
}
},
{
"nested": {
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"instance.instFields.sourceFieldId": "1558"
}
},
{
"term": {
"instance.instFields.fieldString.raw": "challenger"
}
}
]
}
}
}
},
"path": "instance.instFields"
}
}
]
}
}
}
},
"path": "instance",
"inner_hits": {
"name": "inner_data1"
}
}
},
{
"nested": {
"query": {
"bool": {
"should": {
"bool": {
"must": [
{
"match": {
"instance.entitlements.roleId": {
"query": "1",
"type": "boolean"
}
}
},
{
"match": {
"instance.entitlements.read": {
"query": "true",
"type": "boolean"
}
}
}
]
}
}
}
},
"path": "instance.entitlements"
}
}
]
}
}
}
}
}
}
}
resulting docs must return entire instance with all the soureceFields - as on a user page it displays other values of DODGE as well.
now issue is- sort query still has to have knowledge to sort where - "sourceFieldId": 1560 (which is a sourceFieldId for color) to sort on color
is there a way to achieve such a sort query in ES without using dynamic scripting/dynamic templating? something like
"sort": {
"instance.instFields.fieldString.raw": (where sourceFieldId=1560?)
Should be able to achieve this using nested_filter option in sort
From the documentation:
nested_filter A filter that the inner objects inside the nested path
should match with in order for its field values to be taken into
account by sorting. Common case is to repeat the query / filter inside
the nested filter or query. By default no nested_filter is active.
For example to sort on color field it would be:
{
"sort": {
"instance.instFields.fieldValue.raws": {
"order": "asc",
"nested_path": "instance.instFields",
"nested_filter": {
"term": {
"instance.instFields.sourceFieldId": "1560"
}
}
}
}
}
Edited
"sort": [{
"instance.instFields.fieldValue": {
"order": "asc",
"nested_path": "instance.instFields",
"nested_filter": {
"term": {
"instance.instFields.sourceFieldId": "1560"
}
}
}
},
{
"instance.instFields.fieldValue": {
"order": "asc",
"nested_path": "instance.instFields",
"nested_filter": {
"term": {
"instance.instFields.sourceFieldId": "1558"
}
}
}
}
]

Elasticsearch - give negative boost to documents without a certain field

I'm working on a query, the basic filtered multi match query is working as planned, it returns the documents i want.
The issue is that a want to boost results which have a certain string field with ex. 0.5, or in this example give results which don't have this field 'traded_as' a negative boost of 1.0.
Cannot get the filter - boost - must - exists/missing to work as i want.
It this the correct approach on this issue?
Using elasticsearch 1.5.2
{
"query": {
"filtered": {
"query": {
"multi_match": {
"query": "something",
"fields": ["title", "url", "description"]
}
},
"filter": {
"bool": {
"must": {
"missing": {
"field": "marked_for_deletion"
}
}
}
}
}
},
"boosting": {
"positive": {
"filter": {
"bool": {
"must": {
"exists": {
"field": "traded_as"
}
}
}
}
},
"negative": {
"filter": {
"bool": {
"must": {
"missing": {
"field": "traded_as"
}
}
}
}
},
"negative_boost": 1.0
}
}
You cannot have the desired result. As stated in the doc for boosting query :
Unlike the "NOT" clause in bool query, this still selects documents that contain undesirable terms, but reduces their overall score.
{
"query": {
"boosting": {
"positive": [{
"filtered": {
"query": {
"multi_match": {
"query": "something",
"fields": ["title", "url", "description"]
}
},
"filter": {
"bool": {
"must": [{
"missing": {
"field": "marked_for_deletion"
}
}]
}
}
}
}],
"negative": [{
"filtered": {
"filter": {
"missing": {
"field": "traded_as"
}
}
}
}],
"negative_boost": 1.0
}
}
}
So you'll still have some irrelevant documents, but matching documents will have a better score. You won't have any boost on traded_as presence that way. For this you should have a look at function score http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_using_function_score
You would have something like
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"multi_match": {
"query": "something",
"fields": ["title", "url", "description"]
}
},
"filter": {
"bool": {
"must": {
"missing": {
"field": "marked_for_deletion"
}
}
}
}
}
},
"functions": [{
"filter": {
"exists": {
"field": "traded_as"
}
},
"boost_factor": 2
}, {
"filter": {
"missing": {
"field": "traded_as"
}
},
"boost_factor": 0.5
}],
"score_mode": "first",
"boost_mode": "multiply"
}
}
}

ElasticSearch order by _score

How can I order the results by _score?
I can't figure out how to calculate the score for each result, also :)
I managed to write this:
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [
{
"term": {
"type_licitatie": "3"
}
},
{
"term": {
"tip_sursa": "5"
}
}
]
}
}
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
]
}
and this:
{
"query": {
"function_score": {
"query": {
"filtered": {
"filter": {
"bool": {
"should": [
{
"term": {
"country_id": "1"
}
},
{
"term": {
"industry_id": "3"
}
}
]
}
}
}
},
"script_score" : {
"script": "(doc['country_id'].values=1) + (doc['industry_id'].values=3)"
},
"boost_mode": "replace"
}
}
}

Resources