How to get documents that contain certain word in some fields with filtered query? - elasticsearch

I want to find all books with "Agriculture" category. the books should contain word "paddy" in the title OR abstract field.
Here is my query :
GET /books/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"abstract": "paddy"
}
},
{
"match": {
"title": "paddy"
}
}
],
"filter": {
"term": {
"category": "Agriculture"
}
}
}
}
}
those query return all books with "Agriculture" category, even it's contain word "paddy" or not.
What did I do wrong?

Let me first explain to you how, Your query was fetching all the records, even it contains word "paddy" or not. This is b/c you are using the should clause which simply means that The clause (query) should appear in the matching document. but it means it is not forcing that it must appear, hence it's fetching all the documents in your index and then just filtering it on basis of category.
What you need is an upper level must clause, which means it must appear but then I used nested should as it can be either in title or abstract field, but at least one of these fields must contain the value, so that upper level must clause returns true.
The right query is below, which I tried locally and working fine, according to your use case:
{
"query": {
"bool": {
"must": {
"bool": {
"should": [
{
"match": {
"abstract": "paddy"
}
},
{
"match": {
"title": "paddy"
}
}
]
}
},
"filter": {
"term": {
"category": "agriculture"
}
}
}
}
}
Let me know if it's clear to you and solves your issue.

Related

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

Elasticsearch search query: nested query with OR-gates & AND-gates

I have docs as follow:
{
"name": "...",
"country": "...",
}
I need to find. either one of the following criteria:
name=John AND country=US
name=Andy AND country=UK
How should be write this nested query?
Assuming the default fields mapping is defined, you can use boolean queries as follows:
{
"query": {
"bool": {
"should": [
{
"bool": {
"filter": [
{
"term": {
"name.keyword": "John"
}
},
{
"term": {
"country.keyword": "US"
}
}
]
}
},
{
"bool": {
"filter": [
{
"term": {
"name.keyword": "Andy"
}
},
{
"term": {
"country.keyword": "UK"
}
}
]
}
}
]
}
}
}
You should use must instead of filter if you want the query to contribute to the score.
must
The clause (query) must appear in matching documents and will
contribute to the score.
filter
The clause (query) must appear in matching documents. However unlike
must the score of the query will be ignored. Filter clauses are
executed in filter context, meaning that scoring is ignored and
clauses are considered for caching.

Elasticsearch with nested AND/OR query

I'm struggling with writing an elastic search query with multiple AND/OR conditions.
It basically comes to the following logic:
cond1 && (cond2 || cond3 || cond4)
As mentioned in the docs, a document is considered a match if it satisfies only the must clause. The should clauses in this case act as a boost i.e. if a document matches one or more of the should clauses in addition to the must clause, then it will have a higher relevancy score, assuming that cond2, cond3 and cond4 are queries that calculate a relevancy score.
The problem is that I only want documents that also match at least one of the OR conditions.
Note that I'm running ES6.3. I've also tried Multiword queries but these results are also wrong.
Adding boost doesn't seem to affect the results, I have results that only match the first condition.
{
"query": {
"bool": {
"must": [
{
"term": {
"event.keyword": {
"value": "webhook.trigger"
}
}
}
],
"should": [
{
"match": {
"metaData.webhook.title": "My Example Title 1"
}
},
{
"match": {
"metaData.webhook.title": "Testing"
}
},
{
"match": {
"metaData.webhook.url": "myurl.com"
}
}
]
}
}
}
A should query works like a OR only if there is not a must query. In your case you should wrap the should query in another bool query.
{
"query": {
"bool": {
"must": [
{
"term": {
"event.keyword": {
"value": "webhook.trigger"
}
}
},
{
"bool": {
"should": [
{
"match": {
"metaData.webhook.title": "My Example Title 1"
}
},
{
"match": {
"metaData.webhook.title": "Testing"
}
},
{
"match": {
"metaData.webhook.url": "myurl.com"
}
}
]
}
}
]
}
}
}```

ElasticSearch NEST - Search on multiple types but apply filter on selected Type alone

I am looking to achieve a single query for search and filtering. But as expected when i applied filtering, the filter condition applied to all types so i got only the result of those document who have that filtered property and value .
For example,
Here i searched in 3 types (Product,Category,Manufacturer)
GET /my-index/Product,Category,Manufacturer/_search
{
"query": {
"filtered": {
"query": {...}, //--> Search a word which present in all types
"filter": {
"term": {
"ProductField": "VALUE"
}
}
}
}
}
Here i got only the result of Product type because Product type only contains field like 'ProductField' and has value as 'VALUE'.
What i am expecting is, with a single query, fetch all types results(Product,Category,Manufacturer), that satisfying the search query and apply filtering only on Product.
So my doubt is
Is there any way in Elastic search to apply filtering on specific type
search results alone than applying to all types?
Yes, you can use the type query to achieve exactly that. In the filter, we have a bool/should clause that selects either Category or Manufacturer without any other conditions, or Product documents having ProductField: VALUE:
POST /my-index/Product,Category,Manufacturer/_search
{
"query": {
"filtered": {
"query": {},
"filter": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"type": {
"value": "Category"
}
},
{
"type": {
"value": "Manufacturer"
}
},
{
"bool": {
"must": [
{
"type": {
"value": "Product"
}
},
{
"term": {
"ProductField": "VALUE"
}
}
]
}
}
]
}
}
}
}
}

May I search among some fields, but use another field's matching score for sorting?

I have some documents like this
{"id":1,"city":"London","content":"soccer","continent":"Europe"},
{"id":2,"city":"New York","content":"basketball","continent":"North America"},
{"id":3,"city":"Tokyo","content":"baseball","continent":"Asia"},
...
I need to search keywords among some fields(excluding city field), e.g. a query like
{
"query": {
"bool": {
"should": [ //SHOULD_CLAUSE
"match": {
"continent": "America"
},
"term": {
"content": "soccer"
}
]
}
}
}
To make the results more "personalized", I want to make matched documents whose city field is the same as the visiting user's city property.
However, if I make city as a query field(something like "match":{"city":"Tokyo"}) in should boolean clause, it may return some documents that only match the city field, which mismatch the fields I need to search. When using boost to make city field more "important" for sorting things goes worse.
How can I achieve my goal?
It seems that a possible way write the SHOULD_CLAUSE part twice and make one of it combined with city clause using and
{
"query": {
"bool": {
"should": [{
"bool": {
"must": [{
"bool": {
SHOULD_CLAUSE
}
}, {
"match": {
"city": {
"query": "Tokyo",
"boost": 4.0
}
}
}]
}
}, {
"bool": {
SHOULD_CLAUSE
}
}]
}
}
}
But under the real circumstance the SHOULD_CLAUSE part may be more complicated and the whole query seems too long to write. I wonder if there is a better way.
If you want to have only result matching your user city, you should wrap your should query into a must query, something like :
{
"query": {
"bool": {
"must": [{
"bool": {
"should": [{
SHOULD_CLAUSE_1
}, {
SHOULD_CLAUSE_2
}]
}
}, {
"match": {
"city": "Tokyo"
}
}]
}
}
}

Resources