how to search product with elasticsearch - search

This is my DSL:
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "testa",
"analyzer":"standard",
"type": "best_fields",
"fields": [ "name^5", "content^1" ]
}
},
"field_value_factor": {
"field": "popular",
"modifier": "log1p",
"factor": 0.1
},
"boost_mode": "sum",
"max_boost": 1.5
}
}
}
When I search a keyword like 'testa',the result only contains the keyword 'testa',What should I do to make the results contains keywords 'testa' and 'test' or 'tes'?
Thank you.

You can use ngram for partial words search, but you need to reindex your documents.
You can check the official example

You may use Fuzzy Match Query where your query will be like:
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "testa",
"analyzer":"standard",
"fuzziness":"3",
"type": "best_fields",
"fields": [ "name^5", "content^1" ]
}
},
"field_value_factor": {
"field": "popular",
"modifier": "log1p",
"factor": 0.1
},
"boost_mode": "sum",
"max_boost": 1.5
}
}
}
Also, Simple Query String Query might help but you will have to enter your term as "tes*", which may or may not be acceptable to your use case.

Related

Using NOT and OR together in Elastic search

This the query I used in elastic search to filter records that either satisfy one condition or does not satisfy other condition.
{
"query":
{
"query_string":
{
"query": "(NOT col1: \"val1\") OR (col2: val2)",
"analyze_wildcard": true
}}}
The problem is I am not able to write an equivalent syntax in nodejs to extract the information. We cant use must_not here as it is an OR condition
You will make both conditions in should array, as, if anyone matches you will get the record in results, you will have to use must match and must_not match
{
"query": {
"bool": {
"should": [
{
"bool": {
"must_not": {
"match": {
"col1": {
"query": "val1",
"type": "phrase"
}
}
}
}
},
{
"match": {
"col2": {
"query": "val2",
"type": "phrase"
}
}
}
]
}
}
}

ElasticSearch: Bool Query Scoring Issue

I have a query that works probably to search across all fields for phrases separated by spaces with partial matching below. In addition, the scoring works as expected where 'Joh' has a lower score then "John' or 'John Do' has a lower score then "John Doe'
POST /user/_search
{
"query": {
"match": {
"_all": {
"query": "John Doe",
"operator": "or",
"fuzziness": 2,
"prefix_length": 1
}
}
}
}
I am now trying to add a layer on top of this query where it returns the results above where the 'state' field MUST be 'California'. My implementation below returns the desired results but now the scoring has the name score when a match is found. For Example 'Joh' where state = 'California' returns the same score as 'John Doe' where state = 'California'. Why is the scoring no longer working properly? Any solution would be greatly appreciated.
GET /user/_search
{
"query": {
"filtered": {
"query": {
"match": {
"_all": {
"query": "John Doe",
"operator": "or"
},
"filter": {
"bool": {
"must": [
{
"term": {
"state": "California"
}
}
]
}
}
}
}
}
}
}
since you are applying filter, the score will be same for all documents.
https://www.elastic.co/guide/en/elasticsearch/guide/current/function-score-filters.html#_filter_versus_query
Probably you can try using Function Score query

Division of two fields in Elasticsearch

Currently i am trying to group a field based on one field and than getting sum of other fields with respect to the respective field used for grouping. I want to get a new value which needs to be division of the summed field . I will provide the current query i have :
In my query i am aggregating them based on the field ("a_name") and summing "spend" and "gain". I want to get a new field which would be ratio of sum (spend/gain)
I tried adding script but i am getting NaN , also to enable this; i had to enable them first in elasticsearch.yml file
script.engine.groovy.inline.aggs: on
Query
GET /index1/table1/_search
{
"size": 0,
"query": {
"filtered": {
"query": {
"query_string": {
"query": "*",
"analyze_wildcard": true
}
},
"filter": {
"bool": {
"must": [
{
"term": {
"account_id": 29
}
}
],
"must_not": []
}
}
}
},
"aggs": {
"custom_name": {
"terms": {
"field": "a_name"
},
"aggs": {
"spe": {
"sum": {
"field": "spend"
}
},
"gained": {
"sum": {
"field": "gain"
}
},
"rati": {
"sum": {
"script": "doc['spend'].value/doc['gain'].value"
}
}
}
}
}
}
This particular query is showing me a 'NaN' in output. If I replace the division to multiplication the query works.
Essentially what i am looking for is to divide my two aggregators "spe" and "gained"
Thanks!
It might be possible that doc.gain is 0 in some of your documents. You may try changing the script to this instead:
"script": "doc['gain'].value != 0 ? doc['spend'].value / doc['gain'].value : 0"
UPDATE
If you want to compute the ratio of the result of two other metric aggregations, you can do so using a bucket_script aggregation (only available in ES 2.0, though).
{
...
"aggs": {
"custom_name": {
"terms": {
"field": "a_name"
},
"aggs": {
"spe": {
"sum": {
"field": "spend"
}
},
"gained": {
"sum": {
"field": "gain"
}
},
"bucket_script": {
"buckets_paths": {
"totalSpent": "spe",
"totalGained": "gained"
},
"script": "totalSpent / totalGained"
}
}
}
}
}

Elasticsearch sort on multiple queries

I have a query like so:
{
"sort": [
{
"_geo_distance": {
"geo": {
"lat": 39.802763999999996,
"lon": -105.08748399999999
},
"order": "asc",
"unit": "mi",
"mode": "min",
"distance_type": "sloppy_arc"
}
}
],
"query": {
"bool": {
"minimum_number_should_match": 0,
"should": [
{
"match": {
"name": ""
}
},
{
"match": {
"credit": true
}
}
]
}
}
}
I want my search to always return ALL results, just sorted with those which have matching flags closer to the top.
I would like the sorting priority to go something like:
searchTerm (name, a string)
flags (credit/atm/ada/etc, boolean values)
distance
How can this be achieved?
So far, the query you see above is all I've gotten. I haven't been able to figure out how to always return all results, nor how to incorporate the additional queries into the sort.
I don't believe "sort" is the answer you are looking for, actually. I believe you need a trial-and-error approach starting with a simple "bool" query where you put all your criterias (name, flags, distance). Then you give your name criteria more weight (boost) then a little bit less to your flags and even less to the distance calculation.
A "bool" "should" would be able to give you a sorted list of documents based on the _score of each and, depending on how you score each criteria, the _score is being influenced more or less.
Also, returning ALL the elements is not difficult: just add a "match_all": {} to your "bool" "should" query.
This would be a starting point, from my point of view, and, depending on your documents and your requirements (see my comment to your post about the confusion) you would need to adjust the "boost" values and test, adjust again and test again etc:
{
"query": {
"bool": {
"should": [
{ "constant_score": {
"boost": 6,
"query": {
"match": { "name": { "query": "something" } }
}
}},
{ "constant_score": {
"boost": 3,
"query": {
"match": { "credit": { "query": true } }
}
}},
{ "constant_score": {
"boost": 3,
"query": {
"match": { "atm": { "query": false } }
}
}},
{ "constant_score": {
"boost": 3,
"query": {
"match": { "ada": { "query": true } }
}
}},
{ "constant_score": {
"query": {
"function_score": {
"functions": [
{
"gauss": {
"geo": {
"origin": {
"lat": 39.802763999999996,
"lon": -105.08748399999999
},
"offset": "2km",
"scale": "3km"
}
}
}
]
}
}
}
},
{
"match_all": {}
}
]
}
}
}

Boosting matched documents in Elasticsearch which have a certain tag

I have an index of documents that look this:
{
url: "/foo/bar",
html_blocks: [
"<h1>hi</h1>"
],
tags: [
"video",
"text"
],
title: "My title"
}
I'd like to query these documents on the title and html_blocks fields, and for any matches add a boost if they have a video tag.
So far, my query looks like this:
{
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
}
}
How do I modify it so that it continues to only return results if a match is found in the existing query, but a boost is added to any of the results which have a video tag? Thanks!
You want a custom_filters_score which will just boost on matches. Note that filter input is not analyzed, so you might wrap that in a query if you need it analyzed. Your other options to boost, while not really for this case are the boosting query, which is good for demoting results and the custom_score_query which is good for added boosts based on some calculated value.
See: Custom_filters_score
{
"query": {
"custom_filters_score": {
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
},
"filters": [
{
"filter": {
"term": {
"tags": "video"
}
},
"boost": 3
}
]
}
}
}
Edit:
This is what I mean by wrapping in a query using a filter query. Trust me, once you get the hang of ES, you'll be nested so knee deep that you'll produce some of the most satisfying queries ever.
{
"query": {
"custom_filters_score": {
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
},
"filters": [
{
"filter": {
//here comes the filter query, and I changed term to match
//since match analyzes
"query":{
"match": {
"tags": "video"
}
}
},
"boost": 3
}
]
}
}
}

Resources