Elasticsearch sort based on element in multivalue field - sorting

Is it possible to sort based on element existing in multi value field?
Example:
a) document with "111"
put test/test/1
{
"bit_position" : [
1,
2,
3
]
}
b) document with 010
put test/test/2
{
"bit_position": [
2
]
}
Sorting based on "bit_position" = 3 should return document a and then b.
I read about this being possible as nested field but can't find any information about it when bit_position is not nested.
I found this question: Sorting by value in multivalued field in elasticsearch but it has not been answered.
Thank you

I solved this by using function_score:
POST test/_search
{
"query": {
"function_score": {
"match_all": {},
"functions": [
{
"filter": {
"terms": {
"bit_position": [
1,
3
]
}
},
"weight": 2
}
],
"score_mode": "multiply"
}
}
}

Related

Return distinct values in Elasticsearch

I am trying to solve an issue where I have to get distinct result in the search.
{
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}, {
"name" : "ABC",
"favorite_cars" : [ "ferrari","toyota" ]
}, {
"name" : "GEORGE",
"favorite_cars" : [ "honda","Hyundae" ]
}
When I perform a term query on favourite cars "ferrari". I get two results whose name is ABC. I simply want that the result returned should be one in this case. So my requirement will be if I can apply a distinct on name field to receive one 1 result.
Thanks
One way to achieve what you want is to use a terms aggregation on the name field and then a top_hits sub-aggregation with size 1, like this:
{
"size": 0,
"query": {
"term": {
"favorite_cars": "ferrari"
}
},
"aggs": {
"names": {
"terms": {
"field": "name"
},
"aggs": {
"single_result": {
"top_hits": {
"size": 1
}
}
}
}
}
}
That way, you'll get a single term ABC and then nested into it a single matching document

Must match multiple values

I have a query that works fine when I need the property of a document
to match just one value.
However I also need to be able to search with must with two values.
So if a banana has id 1 and a lemon has id 2 and I search for yellow
I will get both if I have 1 and 2 in the must clause.
But if i have just 1 I will only get the banana.
{
"from": 0,
"size": 20,
"query": {
"bool": {
"should": [
{ "match":
{ "fruit.color": "yellow" }}
],
"must" : [
{ "match": { "fruit.id" : "1" } }
]
}
}
}
I havenĀ“t found a way to search with two values with must.
is that possible?
If the document "must" be returned only if the id is 1 or 2, that sounds like another should clause. If I'm understanding your question properly, you want documents with either id 1 OR id 2. Additionally, if the color is yellow, give it a higher score.
Here's one way you might achieve what you're looking for:
{
"query": {
"bool": {
"should": {
"match": {
"fruit.color": "yellow"
}
},
"must": {
"bool": {
"should": [
{
"match": {
"fruit.id": "1"
}
},
{
"match": {
"fruit.id": "2"
}
}
]
}
}
}
}
}
Here I put the two match queries in the should clause of a separate bool query. This achieves the OR behavior you are looking for.
Have another look at the Bool Query documentation and take note of the nuances of should. It behaves differently by default depending on whether or not there is a sibling must clause and whether or not the bool query is being executed in filter context.
Another key option that is adjustable and can help you achieve your expected results is the minimum_should_match parameter. Have a look at this documentation page.
Instead of a match query, you could simply try the terms query for ORing between multiple terms.
Match queries are generally used for analyzed fields. For exact matching, you should use term queries
{
"from": 0,
"size": 20,
"query": {
"bool": {
"should": [
{ "match": { "fruit.color": "yellow" } }
],
"must" : [
{ "terms": { "fruit.id": ["1","2"] } }
]
}
}
}
term or terms query is the perfect way to fetch the exact text or id, using match query result in search inside the id or text
Ex:
id = '4'
id = '44'
Search using match query with id = 4 return both 4 & 44 since it matches 4 in both. This is where terms query come into play.
same search using terms query will return 4 only.
So the accepted is absolutely wrong. Use the #Rahul answer. Just one more thing you need to do, Instead of text you need to analyse the field as a keyword
Example for indexing a field both as a text and keyword (mapping is for flat level for nested change it accordingly).
{
"index_patterns": [ "test" ],
"mappings": {
"kb_mapping_doc": {
"_source": {
"enabled": true
},
"properties": {
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}
using #Rahul's answer doesn't worked because you might be analysed as a text.
id - access a text field
id.keyword - access a keyword field
it would be
{
"from": 0,
"size": 20,
"query": {
"bool": {
"should": [{
"match": {
"color": "yellow"
}
}],
"must": [{
"terms": {
"id.keyword": ["1", "2"]
}
}]
}
}
}
So I would say accepted answer will return falsy results Please use #Rahul's answer with the corresponding mapping.

ElasticSearch: query nested objects, that match filter

I have such index:
{
"id":2,
"name":"test home",
"city_id":"31",
"county_id":"1",
"zip_code":"123",
"residencePlans":[
{
"id" : 1,
"unit_price_from":480240,
"bathrooms_count":3,
"interior_area_sqrft":23,
"floor_range_hight":5,
"bedrooms_count":5,
"elevator_type_id":4,
"price_psqft":3756,
},
{
"id" : 2,
"unit_price_from":123456,
"bathrooms_count":1,
"interior_area_sqrft":12,
"floor_range_hight":4,
"bedrooms_count":2,
"elevator_type_id":3,
"price_psqft":1234,
}
],
}
And then I use some filters. Some of them are applied to the top object, and some to nesting.
I need to query residencePlans, that match filter, applied for their. eg filter on residencePlans.bathrooms_count >= 3 should return only residence with id = 1 and not 2.
{
"id": [2],
"residencePlans.id": [1]
}
I marked residencePlans as nested mapping, but it doesn't help.
Checkout the documentation here: https://www.elastic.co/guide/en/elasticsearch/guide/current/nested-query.html
And here: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-inner-hits.html
Something like this should do it
{
"query": {
"bool": {
"must": [
{ "match": { "id": 1 }},
{
"nested": {
"path": "residencePlans",
"query": {
"bool": {
"must": [
{ "gte": { "residencePlans.unit_price_from": 3 }}
]
}
}
}
}
]
},
inner_hits: {}
}
}
I've revised my answer to take into account the particulars of filtering your top level document and your nested documents. Please let me know if it works for you!

May Elasticsearch nested query return only matched nested documents for nested fields?

I'm new to Elasticsearch, and come up with a question that whether Elasticsearch nested query may return only matched nested documents for nested fields or not.
For Example I have a type named blog with a nested field named comments
{
"id": 1,
...
"comments":[
{"content":"Michael is a basketball player"},
{"content":"David is a soccer player"}
]
}
{
"id": 2,
...
"comments":[
{"content":"Wayne is a soccer player"},
{"content":"Steven is also a soccer player"},
]
}
and the nested query
{"query":{
"nested":{
"path":"comments",
"query":{"match":{"comments.content":"soccer"}}
}
}
What I need is to search blog posts with comments which mentioned "soccer", with the count of comments that matched "soccer" (in the example it counts 1, since another comment just mentioned "basketball") for each blog post.
{"hits":[
{
"id":1,
...
"count_for_comments_that_matches_query":1,
},
{
"id":2,
...
"count_for_comments_that_matches_query":2,
}
]}
However it seems Elasticsearch always return the full document, so how could I achieve it, or I couldn't?
The answer is here.
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-inner-hits.html#nested-inner-hits
You need to use the nested inner hits feature of the Elastic search.
{
"_source": [
"id"
],
"query": {
"bool": {
"must": [
{
"match": {
"id": "1"
}
},
{
"nested": {
"path": "comments",
"query": {
"match": {
"comments.content": "soccer"
}
},
"inner_hits": {}
}
}
]
}
}
}
I think it will solve the problem

Elastic Search - Sort By Doc Type

I have an elastic search index with 2 different doc types: 'a' and 'b'. I would like to sort my results by type and give preference to type='b' (even if it has a low score). I had been consuming the results of the search below at the client end and sorting them but I've realized that this approach does not work well since I am only inspecting the first 10 results which often does not contain any b's. Increasing the return results is not ideal. I'd like to get the elastic search to do the work.
http://<server>:9200/my_index/_search?q=london
You would need to play with function_score and, depending on how you already score your documents, test some weight values, boost_modes and score_modes for each type. For example:
GET /some_index/a,b/_search
{
"query": {
"function_score": {
"query": {
# your query here
},
"functions": [
{
"filter": {
"type": {
"value": "b"
}
},
"weight": 3
},
{
"filter": {
"type": {
"value": "a"
}
},
"weight": 1
}
],
"score_mode": "first",
"boost_mode": "multiply"
}
}
}
Its working for me.you will execute below commands at command Prompt.
curl -XGET localhost:9200/index_v1,index_v2/_search?pretty -d #boost.json
boost.json
{
"indices_boost" : {
"index_v2" : 1.4,
"index_v1" : 1.3
}
}

Resources