Mustache double quotes problem in search templates - elasticsearch

What is the best way to use mustache False values feature in Elasticsearch template?
At the moment I am trying to select function based on boolean value.
Rendering seems to be working according to the logic, but it prints empty double quotes and I cannot get rid of those.
Code example mustache template snippet:
"must": {
"function_score": {
"functions": [
"{{^isLocationFunctionNeeded}}",
{
"exp": {
"location": {
"origin": {
"lat": "0.0",
"lon": "0.0"
},
"offset": "1km",
"scale": "50km"
}
}
},
"{{/isLocationFunctionNeeded}}",
{
"random_score": {},
"weight": 0.00001
}
],
"score_mode": "sum"
}
}
Render snippet:
"must": {
"function_score": {
"functions": [
"",
{
"random_score": {},
"weight": 1.0E-5
}
],
"score_mode": "sum"
}
}
Error I get trying to run the template on ELK:
"error": {
"root_cause": [
{
"type": "parsing_exception",
"reason": "failed to parse [START_OBJECT]. malformed query, expected a [VALUE_STRING] while parsing functions but got a [function_score] instead",
"line": x (where "" is visible in Render snippet),
"col": x (where "" is visible in Render snippet)
}
],
"type": "x_content_parse_exception",
"reason": " x (where "" is visible in Render snippet),[bool] failed to parse field [must]",
"caused_by": {
"type": "parsing_exception",
"reason": "failed to parse [START_OBJECT]. malformed query, expected a [VALUE_STRING] while parsing functions but got a [function_score] instead",
"line": x (where "" is visible in Render snippet),,
"col": x (where "" is visible in Render snippet),
}
Without mustache values it's working fine. Also I noticed in some cases if you surround empty double quotes with random functions it tends to work sometimes. Seems Elastic don't like must cases starting with empty double quotes.
I also asked the same question in ELK community with no luck so far:
https://discuss.elastic.co/t/mustache-double-quotes-problem-in-search-templates/318736
As an example for rendering template we can try using the following:
{
"script": {
"lang": "mustache",
"source": {
"must": {
"function_score": {
"functions": [
"{{^isLocationFunctionNeeded}}",
{
"exp": {
"location": {
"lat": "0.0",
"lon": "0.0"
},
"offset": "1km",
"scale": "50km"
}
},
"{{/isLocationFunctionNeeded}}",
{
"random_score": {},
"weight": 0.00001
}
],
"score_mode": "sum"
}
}
}
}
}
Calling template with params:
{
"id": "example_template",
"params": {
"isLocationFunctionNeeded" : true
}
}

The query inside your template must be a full fledge query, not just must. Also you need to enclose it in triple quotes """, like this, and it will work
POST _scripts/example_template
{
"script": {
"lang": "mustache",
"source": """
{
"query": {
"bool": {
"must": {
"function_score": {
"functions": [
{{^isLocationFunctionNeeded}}
{
"exp": {
"location": {
"lat": "0.0",
"lon": "0.0"
},
"offset": "1km",
"scale": "50km"
}
},
{{/isLocationFunctionNeeded}}
{
"random_score": {},
"weight": 0.00001
}
],
"score_mode": "sum"
}
}
}
}
}
"""
}
}
If you cannot use the triple quotes (e.g. when using Postman), you need to send it as a one-line string and escape all quote characters:
POST _scripts/example_template
{
"script": {
"lang": "mustache",
"source": " { \"query\": { \"bool\": { \"must\": { \"function_score\": { \"functions\": [ {{^isLocationFunctionNeeded}} { \"exp\": { \"location\": { \"lat\": \"0.0\", \"lon\": \"0.0\" }, \"offset\": \"1km\", \"scale\": \"50km\" } }, {{/isLocationFunctionNeeded}} { \"random_score\": {}, \"weight\": 0.00001 } ], \"score_mode\": \"sum\" }}}}"
}
}

Related

Cannot seem to use must and must_not together in an elastic search query

If I run the following query:
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "boxing",
"fuzziness": 2,
"minimum_should_match": 2
}
}
],
"must_not": [
{
"terms_set": {
"allowedCountries": {
"terms": ["gb", "mx"],
"minimum_should_match_script": {
"source": "2"
}
}
}
}
],
"filter": [
{
"range": {
"expireTime": {
"gt": 1674061907954
}
}
},
{
"term": {
"region": {
"value": "row"
}
}
},
{
"term": {
"sourceType": {
"value": "article"
}
}
}
]
}
}
}
against an index with articles that look like:
{
"_index": "content-items-v10",
"_type": "_doc",
"_id": "e7hm75ui4dma1mm4j8q5v7914",
"_score": 4.3724976,
"_source": {
"allowedCountries": ["gb", "ie"],
"body": "Both Joshua Buatsi and Craig Richards join The DAZN Boxing Show ahead of their clash at London's O2 Arena. Matchroom's Eddie Hearn also gives his take on the night, as well as Chantelle Cameron previewing her contest with Victoria Noelia Bustos.",
"competitions": [
{
"id": "8lo6205qyio0fksjx9glqbdhj",
"name": "Buatsi v Richards"
}
],
"contestants": [
{
"id": "7rq59j3eiamxlm12vhxcsgujj",
"name": "Joshua Buatsi"
},
{
"id": "boby9oqe23g6qyuwphrxh8su5",
"name": "Craig Richards"
}
],
"countries": [
{
"id": "7yasa43laq1nb2e6f8bfuvxed",
"name": "World"
},
{
"id": "258l9t5sm55592i08mdpqzr3t",
"name": "United Kingdom"
}
],
"dotsLastUpdateTime": 1673979749396,
"expireTime": 4800000000000,
"fixtureDate": {},
"headline": "Buatsi vs. Richards: Preview",
"id": "e7hm75ui4dma1mm4j8q5v7914",
"importance": 0,
"languageKeys": ["en"],
"languages": ["en"],
"lastUpdateTime": {
"ts": 1653088281000,
"iso8601": "2022-05-20T23:11:21.000Z"
},
"promoImageUrl": null,
"publication": {
"typeId": "1plcw0iyhx9vn1fcanbm2ja3rf",
"typeName": "Shoulder"
},
"publishedTime": {
"ts": 1653088281000,
"iso8601": "2022-05-20T23:11:21.000Z"
},
"region": "row",
"shortHeadline": null,
"sourceType": "article",
"sports": [
{
"id": "2x2oqzx60orpoeugkd754ga17",
"name": "Boxing"
}
],
"teaser": "",
"thumbnailImageUrl": "https://images.daznservices.com/di/library/babcock_canada/45/3e/the-dazn-boxing-show-20052022_xc4jbfqi022l1shq9lu641h9e.png?t=-477976832",
"translations": {}
}
}
I get the following validation error from elasticsearch:
{
"ok": false,
"errors": {
"validation": [
{
"message": "\"query.bool.must_not\" is not allowed",
"path": [
"query",
"bool",
"must_not"
],
"type": "object.unknown",
"context": {
"child": "must_not",
"label": "query.bool.must_not",
"value": [
{
"terms_set": {
"allowedCountries": {
"terms": [
"gb",
"mx"
],
"minimum_should_match_script": {
"source": "2"
}
}
}
}
],
"key": "must_not"
}
}
]
},
"correlationId": "d29e9275-9ab3-4ff8-944d-852b98d4b503"
}
And I cannot figure out what the issue might be! From the elastic docs it should be OK.
I'm using ElasticSearch 7.9.3 running in a local docker container.
I'm hoping someone out there will give me a clue!
Cheers!
I would expect this to just work.
I'm trying to filter out articles that have both of the country codes gb and mx in the field allowedCountries.
I can include them easily enough in the results when I add the terms_set query to the bool.must section of the query.
It works well, you just need to enclose your query in the query section
{
"query": { <--- add this
"bool": { <--- your query starts here
"must": [
...
Thank you for responding!
I was helping with a system I did not have full context on - it turns out there is a proxy in the mix with validation that was blocking the must_not query. So, with the proxy fixed, it now works.

Nested aggregation in nested aggregation query

Having the below (abbreviated) document in Elastic Search 7.1. Focusing on questions.influencerReponse.selectAllThatApplyResponses path.
{
"questions": [
{
"questionId": "79cfc6e7-731e-4d83-9dd6-82f4f39fff03",
"questionKind": "select_all_that_apply",
"questionText": "Have you heard of any of the following charities?",
"questionOptions": {
"1": "Plan International",
"2": "Young Women's Trust",
"3": "Women For Refugee Women",
"4": "The FPA"
},
"influencerReponse": {
"questionId": "79cfc6e7-731e-4d83-9dd6-82f4f39fff03",
"questionKind": "select_all_that_apply",
"text": null,
"questionOrder": 3,
"order": null,
"shortAnswerResponse": null,
"viewerSentimentResponse": null,
"yesNoResponse": null,
"selectAllThatApplyResponses": [
{
"key": "2",
"value": "Young Women's Trust"
}
]
}
}
]
}
I want to get the term aggregations for the key or the value, both are keyword type. I accomplished that before but not in the level of selectAllThatApplyResponses nested type.
Here's what I have so far and throwing the below error.
{
"query": {
"bool": {
"must": [
{
"term": {
"sponsorshipId": {
"value": "33c7140f-23ae-46f2-a0fe-49e2251114e4"
}
}
}
]
}
},
"track_total_hits": true,
"size": 0,
"aggs": {
"select_all_that_apply_responses": {
"nested": {
"path": "questions"
},
"aggs": {
"filter_types": {
"filter": {
"bool": {
"must": [
{
"match": {
"questions.questionId": "79cfc6e7-731e-4d83-9dd6-82f4f39fff03"
}
}
]
}
},
"aggs": {
"select_all_that_apply_nested": {
"nested": {
"path": "questions.influencerReponse.selectAllThatApplyResponses"
},
"aggs": {
"terms": {
"field": "questions.influencerReponse.selectAllThatApplyResponses.key"
}
}
}
}
}
}
}
}
}
I am receiving the below error.
{
"error": {
"root_cause": [
{
"type": "parsing_exception",
"reason": "Expected [START_OBJECT] under [field], but got a [VALUE_STRING] in [terms]",
"line": 42,
"col": 46
}
],
"type": "parsing_exception",
"reason": "Expected [START_OBJECT] under [field], but got a [VALUE_STRING] in [terms]",
"line": 42,
"col": 46
},
"status": 400
}
The final terms agg needs a name too -- I called it select_all_that_apply_nested_terms.
...
"select_all_that_apply_nested":{
"nested":{
"path":"questions.influencerReponse.selectAllThatApplyResponses"
},
"aggs":{
"select_all_that_apply_nested_terms":{
"terms":{
"field":"questions.influencerReponse.selectAllThatApplyResponses.key"
}
}
}
}
...

Function_score, multi_match, script_score, and filter in Elasticsearch

I'm having trouble adding a filter to my existing multimatch query which is embedded inside of a function_score.
Ideally, I'd like to filter by "term" : { "lang" : "en" }, only get back documents which are in the english language.
I've tried moving around the order, tried wrapping my query in bool, but just can't get the filter to work with the other functions I'm using.
My query code:
GET /my_index/_search/
{
"query": {
"function_score": {
"query": {
"bool": {
"filter": {
"term": {
"lang": "en"
}
},
"multi_match": {
"query": "Sample Query here",
"type": "most_fields",
"fields": [
"body",
"title",
"permalink",
"name"
]
}
}
},
"script_score": {
"script": {
"source": "_score + 10"
}
}
}
}
}
Error code:
{
"error": {
"root_cause": [
{
"type": "parsing_exception",
"reason": "[bool] query does not support [multi_match]",
"line": 11,
"col": 19
}
],
"type": "parsing_exception",
"reason": "[bool] query does not support [multi_match]",
"line": 11,
"col": 19
},
"status": 400
}
I'm using the latest version of Elasticsearch (I believe 6.2)
Try wrapping your multi_match in a must clause like so
"must": {
"multi_match": ...
}
The error message is clear, bool query accepts only filter, must, should
Final Solution:
GET /my_index/_search/
{
"query": {
"function_score": {
"query": {
"bool" : {
"filter": {
"term": {
"lang": "en"
}
},
"must" : {
"multi_match" : {
"query": "Sample Query Here",
"type": "most_fields",
"fields": [ "body", "title", "permalink", "name"]
}
}
}
},
"script_score" : {
"script" : {
"source": "_score + 10"
}
}
}
}
}

Elasticsearch (version 2.3) Function Score Query with filtered type query

I am very new to elastic search, We are migrating from Solr to elastic-search. As part of migration working converting existing Solr query to elastic-search DSL query.
Here is the DSL query I have partially completed using function score feature.
{
"query": {
"function_score": {
"query": {
"filtered": {
"match": {
"name": "barack obama"
},
"filter": {
"range": {
"relevance": {
"gte": 6
}
},
"bool": {
"must_not": [
{
"terms": {
"classIds": [
199,
220
],
"execution": "and"
}
}
],
"must": [
{
"term": {
"classIds": 10597
}
}
]
}
}
}
},
"boost_mode": "replace",
"functions": [
{
"script_score": {
"script": {
"lang": "groovy",
"file": "calculate-score",
"params": {
"relevance_boost": 1,
"class_penalize": 0.25
}
}
}
}
]
}
}
}
This query returning error while am running against elastic-search cluster. Please help me to figure out the issue.
Here calculate-score is groovy script and its working fine, I tested that with simple query.
Here is the error response:
{
"error": {
"root_cause": [
{
"type": "query_parsing_exception",
"reason": "[filtered] query does not support [match]",
"index": "nodes_5e27a7d3-b370-40bd-9e71-cf04a36297c0",
"line": 6,
"col": 11
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "nodes_5e27a7d3-b370-40bd-9e71-cf04a36297c0",
"node": "NOAwAtVwQS25egu7AIaHEg",
"reason": {
"type": "query_parsing_exception",
"reason": "[filtered] query does not support [match]",
"index": "nodes_5e27a7d3-b370-40bd-9e71-cf04a36297c0",
"line": 6,
"col": 11
}
}
]
},
"status": 400
}
Here is Solr query I am trying to convert to elastic-search:
SOLR QUERY (UNIQUE_NODE_CORE): q={!boost b="product(pow(field(relevance),1.0000),if(exists(query({!v='all_class_ids:226'})),0.25,1),if(exists(query({!v='all_class_ids:14106'})),0.25,1),if(exists(query({!v='all_class_ids:656'})),0.25,1))"}
raw_name:"barack obama"
&rows=1
&start=0
&sort=score desc,relevance desc
-&fq=class_id:"10597"
-fq=relevance:[6 TO *]
-&fq=-all_class_ids:"14127"
-&fq=-all_class_ids:"14106"
-&fq=-all_class_ids:"226"
&fl=ontology_id,url_friendly_name,name,score,raw_notable_for,property_207578
Just need help to run filtered query with function score.
Great job, you're almost there, you're just missing a query section inside your filtered query in order to wrap the match query. As well, the range filter can be inserted into the bool/must. Quite a mouthful, I know.
{
"query": {
"function_score": {
"query": {
"filtered": {
"query": {
"match": {
"name": "barack obama"
}
},
"filter": {
"bool": {
"must_not": [
{
"terms": {
"classIds": [
199,
220
],
"execution": "and"
}
}
],
"must": [
{
"range": {
"relevance": {
"gte": 6
}
}
},
{
"term": {
"classIds": 10597
}
}
]
}
}
}
},
"boost_mode": "replace",
"functions": [
{
"script_score": {
"script": {
"lang": "groovy",
"file": "calculate-score",
"params": {
"relevance_boost": 1,
"class_penalize": 0.25
}
}
}
}
]
}
}
}
Note that since ES 2.0 the filtered query is deprecated and you can rewrite it with a bool/must/filter query like this:
{
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"match": {
"name": "barack obama"
}
},
"filter": [
{
"range": {
"relevance": {
"gte": 6
}
}
},
{
"term": {
"classIds": 10597
}
}
],
"must_not": [
{
"terms": {
"classIds": [
199,
220
],
"execution": "and"
}
}
]
}
},
"boost_mode": "replace",
"functions": [
{
"script_score": {
"script": {
"lang": "groovy",
"file": "calculate-score",
"params": {
"relevance_boost": 1,
"class_penalize": 0.25
}
}
}
}
]
}
}
}

Function Score On Nested Object

I have this index blog with the following settings and mappings.
PUT /blog
{
"settings": {
"index": {
"number_of_shards": "1"
}
},
"mappings": {
"post": {
"_all": {
"enabled": false
},
"properties": {
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"visitor": {
"type": "nested",
"properties": {
"id": {
"type": "string",
"index": "not_analyzed"
},
"last_visit": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
}
}
}
I want to rank my posts based on relevancy and visitor's last visit. I tried this query without success. It seems like the gauss function cannot get the value of visitor's last_visit. How to get this worked?
POST /blog/post/_search
{
"query": {
"function_score": {
"functions": [
{
"gauss": {
"visitor.last_visit": {
"origin": "now/d",
"offset": "3d",
"scale": "4d",
"decay": 0.5
}
},
"filter": {
"nested": {
"path": "visitor",
"query": {
"term": {
"visitor.id": "1"
}
}
}
}
}
]
}
}
}
Here is a query with a match for a name that uses a nested object that I had for a particular use case. I didn't use any date fields, but as I said, it does use a nested object. I used relevancy of distance along with a text match, so it's similar.
I used the answer from this question to structure my query as it matched what I was trying to do. Scoring documents by text match and distance
GET dev_search_core_data/_search?size=200
{
"query": {
"bool": {
"should": [
{
"match": {
"NAME": "Amy Smith"
}
},
{
"bool": {
"must": [
{
"function_score": {
"query": {
"nested": {
"path": "LOCATION",
"query": {
"term": {
"LOCATION.SOME_IND": {
"value": true
}
}
}
}
},
"functions": [
{
"gauss": {
"LOCATION.COORDINATES": {
"origin": "-118.309, 34.041",
"scale": "50km",
"offset": "10km",
"decay": 0.5
}
}
}
]
}
}
]
}
}
]
}
}
}
I think the problem is with the structure of your query. I always run this command first to validate my queries if I'm having any problems to eliminate any syntax issues.
GET dev_search_core_data/_validate/query?explain
This was the result:
{
"valid": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"explanations": [
{
"index": "dev_search_core_data_b",
"valid": true,
"explanation": "filtered((NAME:amy NAME:smith) (+function score (ToParentBlockJoinQuery (filtered(LOCATION.SOME_IND:true)->random_access(_type:_LOCATION)),function=org.elasticsearch.index.query.functionscore.DecayFunctionParser$GeoFieldDataScoreFunction#274227b9)))->cache(org.elasticsearch.index.search.nested.NonNestedDocsFilter#1012ada6)"
}
]
}
I also looked at the docs for an in-depth explanation of how the function score worked. You don't mention your version, but I'm using ES 1.6.

Resources