Bool query not working as expected - elasticsearch

POST /test/topic/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "Predisposition",
"fields": [
"_all"
]
}
},
{
"multi_match": {
"query": "thrombosis",
"fields": [
"_all"
]
}
}
],
"should": [
{
"multi_match": {
"query": "cancer",
"fields": [
"_all"
]
}
}
]
}
}
}
My understanding of the above query is that it must match on predisposition AND thrombosis OR cancer, however I'm only getting a handful of documents that match on predisposition AND thrombosis, I was expecting lots of cancer documents but have zero. What am I missing?

The must needs to always match. should will only give a boost to the score if it matches.
Also, there is another case when there are no must statements and in this case at least one should must match.
I think you are looking for the following, instead:
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"multi_match": {
"query": "Predisposition",
"fields": [
"_all"
]
}
},
{
"multi_match": {
"query": "thrombosis",
"fields": [
"_all"
]
}
}
]
}
},
{
"bool": {
"must": [
{
"multi_match": {
"query": "cancer",
"fields": [
"_all"
]
}
}
]
}
}
]
}
}
}

The way you are searching is, documents must have predisposition AND thrombosis regardless of cancer because they are inside must filter.
You basically need to wrap your must clause inside should clause like this
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"multi_match": {
"query": "predisposition",
"fields": "_all"
}
},
{
"multi_match": {
"query": "thrombosis",
"fields": "_all"
}
}
]
}
},
{
"multi_match": {
"query": "cancer",
"fields": "_all"
}
}
]
}
}
}
This will give you the desired results.

Related

How to write query to find data in nested and not nested fields together

I would like to find multiple field search.
So:
GET my_doc/_search
{
"query": {
"multi_match" : {
"query": "text",
"fields": [ "state", "city"]
}
}
}
Generally this query works, but it does not search in the nested fields.
But this one works only for nested fields:
GET my_doc*/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "images",
"score_mode": "max",
"query": {
"bool": {
"must": [
{"match": {"images.description": "Subject" }},
{"match": {"images.Number": "10004" }}
]
}
}
}
}
]
}
}
}
My question is:
How to write query to search everywhere - Just to join my queries together to find in the "images" location too.
I've found solution, just to join queries:
GET my_doc*/_search
{
"query": {
"bool": {
"must": [
{
"multi_match" : {
"query": "LAKE",
"fields": [ "state", "city"]
}
},
{
"nested": {
"path": "images",
"score_mode": "max",
"query": {
"bool": {
"must": [
{"match": {"images.description": "Subject" }},
{"match": {"images.Number": "10004" }}
]
}
}
}
}
]
}
}
}

How to use query_string with the filter in elasticsearch?

I have a simple query
GET data/_search
{
"query": {
"bool": {
"must": [
{
"prefix": {
"last_name": "test"
}
},
{
"bool": {
"should": {
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
}
}
]
}
}
}
I would like to change the query_string to a filter. I'm not sure how to convert
{
"bool": {
"should": {
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
}
}
into something like
"filter": {
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
and make sure it filters by all this cities henderson OR Boulder City OR Sloan and by all this fields city_*.keyword
Any ideas?
Change
{
"bool": {
"should": {
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
}
}
to
{
"bool": {
"filter": {
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
}
}
Does this get your desired behavior? Using the same query under a filter should give you the same results as should, but the scoring will not be weighted by the query.
Edit - One more recommendation I would make is to adjust your query to this:
GET data/_search
{
"query": {
"bool": {
"must": [
{
"prefix": {
"last_name": "test"
}
}
],
"filter": [
{
"query_string": {
"query": "henderson OR Boulder City OR Sloan",
"fields": [
"city_*"
]
}
}
]
}
}
}
Edit 2 - You may be able to move away from using query_string, does this give you any speed increase? (you could change should to the "shoulds" to be nested within a filter as well if you want them unscored)
GET data/_search
{
"query": {
"bool": {
"must": [
{
"prefix": {
"last_name": "test"
}
}
],
"should": [
{
"match": {
"city_*": "henderson"
}
},
{
"match": {
"city_*": "Boulder City"
}
},
{
"match": {
"city_*": "Sloan"
}
}
]
}
}
}

Elastic Search - OR querying for non matches

I'm having trouble querying in elastic search. I'm searching over a specific set of data defined by the state_id, and then wanting to return all the states which do not have either one of the cities defined by the identifiers below.
The query below returns 18 results with just "city_id_1", and 0 results with "city_id_2". With both though, I return 0 results (since "city_id_2" is on every state record). What I want to do is still return the 18 results, but query over both cities.
I feel like my query should be working, and basically doing a NOT (A or B) style query, equivalent to NOT A and NOT B, but basically the 0 results seems to be overriding the 18.
Is there a way I can change my query to get the results I want, or is this something elasticsearch cannot do?
{
"query": {
"bool": {
"must": [
{ "terms": { "state_id": ["4ca16f80-da79-11e5-9874-64006a4f57cb"]}}
],
"must_not": [
{
"nested": {
"path": "cities",
"query": {
"bool": {
"should": [
{"term": { "cities.identifier": "city_id_1"}},
{"term": { "cities.identifier": "city_id_2"}}
]
}
}
}
}
]
}
},
"size": 10
}
Try this on for size. Elasticsearch is silly. The filter needs to be in each of the nested queries.
{
"query": {
"bool": {
"should": [
{
"query": {
"bool": {
"must_not": [
{
"nested": {
"path": "cities",
"query": {
"term": { "cities.identifier": "city_id_1"}
}
}
}
],
"filter":[
{
"term":{
"state_id":"4ca16f80-da79-11e5-9874-64006a4f57cb"
}
}
]
}
}
},
{
"query": {
"bool": {
"must_not": [
{
"nested": {
"path": "cities",
"query": {
"term": { "cities.identifier": "city_id_2"}
}
}
}
],
"filter":[
{
"term":{
"state_id":"4ca16f80-da79-11e5-9874-64006a4f57cb"
}
}
]
}
}
}
]
}
},
"size": 10
}
If you want NOT A AND NOT B behaviour you need to make a little change
{
"query": {
"bool": {
"must": [
{ "terms": { "state_id": ["4ca16f80-da79-11e5-9874-64006a4f57cb"]}}
],
"must_not": [
{
"nested": {
"path": "cities",
"query": {
"bool": {
"must": [ ====> Use must instead of should
{"term": { "cities.identifier": "city_id_1"}},
{"term": { "cities.identifier": "city_id_2"}}
]
}
}
}
}
]
}
},
"size": 10
}
This will exclude those record which will have both city_id_1 and city_id_2.
As per my understanding, you are looking our for NOT A or NOT B kind of a clause. Please check the query below and see if it fits your requirement
{
"query": {
"bool": {
"must": [
{ "terms": { "state_id": ["4ca16f80-da79-11e5-9874-64006a4f57cb"]}}
],
"should": [
{
"nested": {
"path": "cities",
"query": {
"bool": {
"must_not": [
{"term": { "cities.identifier": "city_id_1"}}
]
}
}
}
},
{
"nested": {
"path": "cities",
"query": {
"bool": {
"must_not": [
{"term": { "cities.identifier": "city_id_2"}}
]
}
}
}
}
],
"minimum_number_should_match": 1
}
},
"size": 10
}

Elasticsearch Parse Exception for boolean queries

I'm trying to create queries similar to kibana queries in elasticsearch lucene queries. What I'm basically trying to do is matching some phrases. For example; my kibana query looks like this:(+"anna smith") AND ( (+"university"), (+"chairman"), (+"women rights")) It searches "anna smith" as must and one of the other phrases as should(there should be at least one of them exist in the text). I wrote a query to do this but it gives "elasticsearch parse exception:expected field name but got start_object". How can I solve this. Here is my query;
{
"query": {
"bool": {
"must": {
"match": {
"text": {
"query": "anna smith",
"operator": "and"
}
}
}
},
"query": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"match": {
"text": {
"query": "university",
"boost": 2
}
}
},
{
"match": {
"text": {
"query": "chairman",
"boost": 2
}
}
}
]
}
}]
}}}}
Your second query at the bottom cannot be there, it needs to be inside the first bool/must like this
{
"query": {
"bool": {
"must": [
{
"match": {
"text": {
"query": "anna smith",
"operator": "and"
}
}
},
{
"bool": {
"should": [
{
"match": {
"text": {
"query": "university",
"boost": 2
}
}
},
{
"match": {
"text": {
"query": "chairman",
"boost": 2
}
}
}
]
}
}
]
}
}
}

How to distinguish hits of several should clauses

I have a query with several "should" clauses:
{
"query": {
"filtered": {
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "<condition1>"
}
},
{
"query_string": {
"query": "<condition1>"
}
}
]
}
},
}
},
"size": 1000,
"sort": [
{
"#timestamp": {
"order": "asc"
}
}
]
}
How can I find out which query results were produced by condition1, and which by condition2? Is it possible to inject a field with different values for different conditions, or distinguish hits in any other way?
You can use named queries to achieve this.
{
"query": {
"bool": {
"should": [
{
"query_string": {
"query": "<condition1>",
"_name": "sub_query_1"
}
},
{
"query_string": {
"query": "<condition1>",
"_name": "sub_query_2"
}
}
]
}
}
}
You result will then contain a matched_filters array with either sub_query_1, sub_query_2, or both in it.
Update
Play link: https://www.found.no/play/gist/af1a1fa2b5cf3aa279b1

Resources