Elasticsearch : Improving multi_match results - elasticsearch

Hi I am trying to search a value in a different fields. I am using multi_match with cross_fields type.
Here is the query
"query": {
"filtered": {
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "red cross",
"type": "cross_fields",
"fields": [
"name^20",
"keywords^12",
"description^1"
]
}
}
]
}
}
} }
Results I am getting for the above query
"results": [
{
"name": "CrossPurpose",
.....
} ,
{
"name": "Community Center",
"keywords": "American Red Cross,Red Cross,Center,Blood",
. . .
},
{
"name": "Some Group",
"description":".... red cross ..."
},
.......
....
..
{
"name" : "Red cross" ,
.....
}
]
I want to improve the search results.
I want to see the record with name "Red cross" in the first position.
First it should match as whole word "red cross" then only it should match "red" , "cross".
I want preference to be given more for name field than keywords and description.
Please help me to improve the query .
Thanks in advance.

You need to use type = best_fields
so your query will be
{
"query": {
"multi_match" : {
"query": "red cross",
"type": "best_fields",
"fields": [ "name", "keywords", "description" ],
"tie_breaker": 0.3
}
}
}

Related

Elastic Search : Search keyword results of a specific category

I'm trying to build a query where I'm trying to search for names of people of a specific country. If I provide input as John and USA, I should only find results of people by the name John (by the property : name) from USA (by the property : country) and results from other countries shouldn't appear in the results.
What I have tried :
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "John",
"fields": ["username", "first_name", "last_name"],
"fuzziness": "AUTO",
"minimum_should_match": "50%"
}
}
],
"filter": [
{
"match": {
"country": "USA"
}
},
{
"match": {
"is_citizen": true
}
}
]
}
}
With the above query the problem I'm seeing is that the results also show people **who don't have their name as John but are from USA
**.
Expectation : To filter results of given keyword specific to given country.
Instead of using should you need to use must clause in your name query.
Below query should give you expected results. refer boolean query official doc to understand the difference with examples.
"query": {
"bool": {
"must": [ --> note `must` here
{
"multi_match": {
"query": "John",
"fields": ["username", "first_name", "last_name"],
"fuzziness": "AUTO",
"minimum_should_match": "50%"
}
}
],
"filter": [
{
"match": {
"country": "USA"
}
},
{
"match": {
"is_citizen": true
}
}
]
}
}
You are using should clause thats why it is not working. You can use must insted of should and it will resolved your issue.
You can use "type":"phrase_prefix" to match Jo with John.
You can change your query as shown below and it will work:
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "John",
"fields": ["username", "first_name", "last_name"],
"type":"phrase_prefix",
"minimum_should_match": "50%"
}
}
],
"filter": [
{
"match": {
"country": "USA"
}
},
{
"match": {
"is_citizen": true
}
}
]
}
}

Elastic Search exact match query with wildcard search for multiple fields

I have elastic search data store like below, and I need to write multi search ES query through these data with exact match and exact match + *(wildcard)
[
{
"id": "123",
"name": "test123 abc bct",
"externalObj": {
"id": "abc 123"
}
},
{
"id": "124",
"name": "test124 abc bct",
"externalObj": {
"id": "abc 124"
}
}
]
currently i have written query like below,
{
"query": {
"query_string": {
"fields": [
"name^5",
"id",
"externalObj.*"
],
"query": "(test124 abc)",
"default_operator": "AND"
}
}
}
Above query is working fine with exact match but I need to get the data for partial search and maximum relevant score for the response as well. that thing doesn't work with this query.
e.g: "query": "test124 ab"
Can anyone help me out for above problem ?
There are 2 options to achieve what you want. You can choose one of them to use:
Set default_operator to OR (or just simply remove it since the default value is OR).
{
"query": {
"query_string": {
"fields": [
"name^5",
"id",
"externalObj.*"
],
"query": "test124 a"
}
}
}
Change your query into test124 a*
{
"query": {
"query_string": {
"fields": [
"name^5",
"id",
"externalObj.*"
],
"query": "test124 a*",
"default_operator": "AND"
}
}
}

How to boost exact match on multi match in elastic search

I have several documents with a field name title contain value like foo bar and foo:bar.
I'm trying to boost an exact match foo:bar documents and sort the result according to the score.
Here is my attempt, any help would be appreciated.
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "",
"fields": [
"title",
]
}
}
],
"should": [
{
"multi_match": {
"query": "",
"fields": [
"title",
]
"type": "phrase"
"boost": 20
}
}
],
}
}

How to boost certain documents if the search query contains a certain term/text in elastic

If the search query contains fruits I want to boost the products from a certain category?
{
"query": {
"bool": {
"should": [
{
"constant_score": {
"boost": 2,
"filter": {
"term": { "categories": "3" }
}
}
}
]
}
}
}
I have the above query, which gives a constant score to items with the category 3, I want to apply this constant score/boosting/increase relevancy only when a certain text (for example fruits) is present in the search term.
Sample elasticsearch document
{
"id" : 1231,
"name" : {
"ar" : "Arabic fruit name",
"en" : "english fruit name"
}
"categories" : [3,1,3] // category ids because the same product is shown in multiple categories
}
How do I achieve this? I use elasticsearch 7.2
Original answer:
{
"query": {
"bool": {
"should": [
{
"constant_score": {
"boost": 2,
"filter": {
"bool": {
"filter": [
{
"term": {
"categories": "3"
}
}
],
"should": [
{
"match": {
"name.ar": "fruit"
}
},
{
"match": {
"name.en": "fruit"
}
}
],
"minimum_should_match": 1
}
}
}
}
]
}
}
}
If i understand correctly what you're looking for.
Btw, I suggest using "match_phrase" instead of "match" if you want to match "fruit name" exactly and not "fruit" or "name"
Update: (based on the comment)
In that case i'd suggest reorganizing your schema in the following manner:
"item": {
"properties": {
"name": {
"type": ["string"]
},
"language": {
"type": ["string"]
}
}
}
So your sample would become:
{
"id" : 1231,
"item" : [
{"name": "Arabic fruit name", "language": "ar"}
{"name": "english fruit name", "language": "en"}
],
"categories" : [3,1,3]
}
And then you can match against "item.name"
Why? Because the way ElasticSearch indexes (at least, by default) is to flatten your the array, so internally it looks like ["Arabic fruit name", "english fruit name"]
With your original sample, two different fields are created in the schema (name.ar and name.en), which is actually not a great design if you need to scale

Querying fields with AND in ElasticSearch

In my ElasticSearch document index I have a property type like
type= LOCATION | PERSON | TIME
and a text field that represents the whole document.
To search for types like LOCATION and a specific text like `Mountain View" I do like
doc.text:Mountain View AND doc.type:LOCATION
If I want to do a OR query I would use instead the query_string approach like
"query": {
"query_string": {
"query": "entity.text: (Mountain View OR Menlo Park) AND entity.type:LOCATION"
}
}
This works as well. To do AND queries, like searching for item.text having both "Mountain View" and "Menlo Park" for a item.type=LOCATION, it does not work doing like
"query": {
"query_string": {
"query": "entity.text: (California AND Nevada) AND entity.type:LOCATION"
}
}
Other attempts were:
Using bool clause with should like:
{
"query": {
"bool": {
"should": [
{ "match": { "text": "Menlo Park" }},
{ "match": { "text": "Mountain View" }}
]
}
}
}
Using cross-fields with multi_match
"query": {
"multi_match": {
"query": "California Nevada",
"type": "cross_fields",
"operator": "AND",
"fields": [
"text"
]
}
}
Another approach was using must with the latter (in this case omitting the type by the way):
{
"query": {
"bool": {
"must": [
{
"multi_match" : {
"query": "Nevada",
"type": "cross_fields",
"fields": [ "text"],
}
},
{
"multi_match" : {
"query": "California",
"type": "cross_fields",
"fields": [ "text" ]
}
}
]
}
}
}
but it returns no results neither. Note that in the last case using should instead of must will produce an OR query that will work ok.
So how to perform an AND query on the same field text to match multiple values like California and Nevada?
If I understood the question right, I would do the following:
{
"query": {
"bool" : {
"must": [
"match" : {
"text" : {
"query" : "California Nevada",
"operator" : "and"
}
}
]
}
}
}
Documentation
Hope it helps!

Resources