Elasticsearch query to filter document by specific field value with conditions - elasticsearch

I want to filter brand names if supplied but return all brands if the filter is empty.
here is my query.
"query": {
"bool": {
"must": [
{
"terms": {
"seller": [
"Seller1",
"Seller2"
]
}
},
{
"bool": {
"should": [
{
"terms": {
"brand": [
"brand1"
]
}
},
{
"bool": {
"must_not": [
{
"term": {
"brand": {
"value": ""
}
}
}
]
}
}
]
}
},
{
"nested": {
"path": "Stock",
"query": {
"bool": {
"must": {
"match": {
"region": "Regional"
}
},
"filter": [
{
"term": {
"pincode": "12345"
}
}
]
}
}
}
}
]
}
}
I want if (brand == ["brand1","brand2"]) return those brand products only. But if supplied empty return all. I tried to use it with should, still getting everything if brand is supplied.

There are multipul ways and some of are mentioned below:
Option 1:
You can handle this logic of include, exclude at the application level while creating queries. If you are using Java or python client then it is easily achievable. If you are calling direct search API of elasticsearch then you can not add brand term clause while calling api.
Option 2:
You can use the search template functionality of Elasticsearch.
First you need to create search template as shown in below example:
PUT _scripts/my-search-template
{
"script": {
"lang": "mustache",
"source": """{
"query": {
"bool": {
"must": [
{
"terms": {
"seller": [
"seller1",
"seller2"
]
}
}
],
"filter": [
{{#filter}}
{
"terms": {
"{{name}}":
{{#toJson}}value{{/toJson}}
}
}{{/filter}}
]
}
}
}"""
}
}
You can use below API to search using search template, here if you dont pass brand in filter it will not add in actual query:
POST querycheck/_search/template
{
"id": "my-search-template",
"params": {
"filter": [
{
"name": "brand",
"value": [
"brand1",
"brand2"
]
}
]
}
}
You can use render api as well to check if query template is generating query correct or not.
POST _render/template
{
"id": "my-search-template",
"params": {
"filter": [
{
"name": "brand",
"value": [
"brand1",
"brand2"
]
}
]
}
}

Related

How to apply combination of filters on array of objects in elasticsearch?

Hi Please help me to write a suitable query for my task, I have list of products with different categories and associated attribute and tags. Here is two documents for two categories along with associated attribute list. There could be multiple attributes, just showing one.
{
"category": "blouses",
"attributes": [
{
"attribute": "women-blouse-neckline",
"tag": "round-neck"
}
]
}
{
"category": "dresses",
"attributes": [
{
"attribute": "women-dress-neckline",
"tag": "v-neck"
}
]
}
Now I want to get list of products from both categories which are dresses and blouses, but along with that a specific case at attribute level is :
Fetch all the products from dresses where attribute is women-dress-neckline and tag is v-neck along with all the products from blouses where attribute is women-blouse-neckline and tag is round-neck.
Thanks.
To query on each key of "attributes", you need to define "attributes" to be of the nested type, and then use a combination of bool/must and nested query
Adding a working example with index mapping, search query and search result
Index Mapping:
{
"mappings": {
"properties": {
"attributes": {
"type": "nested"
}
}
}
}
Search Query:
{
"query": {
"bool": {
"must": [
{
"match": {
"category": "dresses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-dress-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "v-neck"
}
}
]
}
}
}
}
]
}
}
}
Search Result:
"hits": [
{
"_index": "69611494",
"_type": "_doc",
"_id": "2",
"_score": 2.0794413,
"_source": {
"category": "dresses",
"attributes": [
{
"attribute": "women-dress-neckline",
"tag": "v-neck"
}
]
}
}
]
Update 1:
You can combine two nested queries as shown below
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"match": {
"category": "dresses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-dress-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "v-neck"
}
}
]
}
}
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"category": "blouses"
}
},
{
"nested": {
"path": "attributes",
"query": {
"bool": {
"must": [
{
"term": {
"attributes.attribute.keyword": "women-blouse-neckline"
}
},
{
"term": {
"attributes.tag.keyword": "round-neck"
}
}
]
}
}
}
}
]
}
}
]
}
}
}

How to create an ElasticSearch Query which should not match any of multiple categories

I'm looking for documents inside elasticSearch which do not match one or the other brand, but fullFill a fix requirement. I'm looking for any entries which are not from Toyota, BMW or Audi. But the entry must be a superEntry (exact match)
The following Query is what I'm working on:
"query": {
"bool": {
"filter": {
"term": {
"superEntry": true
}
},
"must": {
"bool": {
"must_not": [
{
"term": {
"brand": "Toyota"
}
},
{
"term": {
"brand": "BMW"
}
},
{
"term": {
"brand": "Audi"
}
}
]
}
}
}
}
}
Expected: I find any super-entries from any other brand, but not from those 3. The query above still lists me cars from BMW as an example..
Not tested but something like this will help-
{
"size": 10,
"query": {
"bool": {
"must": [
{
"match": {
"superEntry": true
}
}
],
"must_not": [
{
"terms": {
"brand": [
"Toyota",
"BMW",
"Audi"
]
}
}
]
}
}
}

Should as filter context (OR without scoring in Elasticsarch possible?)

I am trying to setup most efficient way to build an OR without having a scoring, since I want to order my results by business values afterwards.
Unfortunately i don't get it done. :(
What I need:
COLOR=X AND ( title = Y OR description = Z)
What I tried (but it is malformed):
{
"query": {
"bool": {
"filter": [
{
"term": {
"colors.source_name": "braun"
}
},
{
"should": [
{
"term": {
"title": "sofa"
}
},
{
"term": {
"description": "sofa"
}
}
]
}
]
}
}
What I also tried, but it also provided results without "gartenlounge", and especially with scoring:
{
"query": {
"bool": {
"filter": [
{
"term": {
"colors.source_name": "braun"
}
}
],
"should": [
{
"term": {
"title": "sofa"
}
},
{
"term": {
"description": "sofa"
}
}
]
}
}
The following query should work for you:
{
"query": {
"bool": {
"filter": [
{"term": {
"colors.source_name": "braun"
}},
{"bool": {
"should": [
{"term": {"title": "sofa"}},
{"term": {"description": "sofa"}}
]
}}
]
}
}
}
You can nest a bool query inside the filter context, and should is only valid from within a bool clause.
It's an old reference sir, but it still checks out:
https://www.elastic.co/guide/en/elasticsearch/guide/current/combining-filters.html

Match multiple properties on the same nested document in ElasticSearch

I'm trying to accomplish what boils down to a boolean AND on nested documents in ElasticSearch. Let's say I have the following two documents.
{
"id": 1,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "anotheruser#domain.com"
}
]
},
{
"thirdLevels": [
{
"isActive": false,
"user": "user#domain.com"
}
]
}
]
}
{
"id": 2,
"secondLevels": [
{
"thirdLevels": [
{
"isActive": true,
"user": "user#domain.com"
}
]
}
]
}
In this case, I want to only match documents (in this case ID: 2) that have a nested document with both isActive: true AND user: user#domain.com.
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
}
}
}
]
}
}
}
However, what seems to be happening is that my query turns up both documents because the first document has one thirdLevel that has isActive: true and another thirdLevel that has the appropriate user.
Is there any way to enforce this strictly at query/filter time or do I have to do this in a script?
With nested-objects and nested-query, you have made most of the way.
All you have to do now is to add the inner hits flag and also use source filtering for move entire secondLevels documents out of the way:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "secondLevels.thirdLevels",
"query": {
"bool": {
"must": [
{
"term": {
"secondLevels.thirdLevels.isActive": true
}
},
{
"term": {
"secondLevels.thirdLevels.user": "user#domain.com"
}
}
]
}
},
"inner_hits": {
"size": 100
}
}
}
]
}
}
}

Elastic search DSL Syntax equivalence for SQL statement

I'm trying to replicate the below query logic in an elastic search query but something's not right.
Basically the query below returns one doc. I'd like either the first condition to be applied: "name": "iphone" OR the more complex second one which is: (username = 'gogadget' AND status_type = '1' AND created_time between 4532564 AND 64323238). Note that the nested bool must inside the should would take care of the more complex condition. I should still see 1 doc if I change the outside match of "name": "iphone" to be changed to "name": "wrong value". But I get nothing when I do that. I'm not sure where this is wrong.
The SQL Query is here below.
SELECT * from data_points
WHERE name = 'iphone'
OR
(username = 'gogadget' AND status_type = '1' AND created_time between 4532564 AND 64323238)
{
"size": 30,
"query": {
"bool": {
"must": [
{
"bool": {
"minimum_should_match": "1",
"should": [
{
"bool": {
"must": [
{
"match": {
"username": "gogadget"
}
},
{
"terms": {
"status_type": [
"3",
"4"
]
}
},
{
"range": {
"created_time": {
"gte": 20140712,
"lte": 1405134711
}
}
}
]
}
}
],
"must": [],
"must_not": []
}
},
{
"match": {
"name": "iphone"
}
}
]
}
}
}
should query will match the query and return.
You don't need use must to aggregate your OR query.
The query should like:
{
"query": {
"bool": {
"should": [{
"bool": {
"must": [{
"match": {
"username": "gogadget"
}
}, {
"terms": {
"status_type": [
"3",
"4"
]
}
}, {
"range": {
"created_time": {
"gte": 20140712,
"lte": 1405134711
}
}
}]
}
}, {
"match": {
"name": "iphone"
}
}]
}
}
}

Resources