| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 | [[query-dsl-script-score-query]]=== Script score query++++<titleabbrev>Script score</titleabbrev>++++Uses a <<modules-scripting,script>> to provide a custom score for returneddocuments.The `script_score` query is useful if, for example, a scoring function is expensive and you only need to calculate the score of a filtered set of documents.[[script-score-query-ex-request]]==== Example requestThe following `script_score` query assigns each returned document a score equal to the `likes` field value divided by `10`.[source,console]--------------------------------------------------GET /_search{  "query": {    "script_score": {      "query": {        "match": { "message": "elasticsearch" }      },      "script": {        "source": "doc['likes'].value / 10 "      }    }  }}--------------------------------------------------[[script-score-top-level-params]]==== Top-level parameters for `script_score``query`::(Required, query object) Query used to return documents.`script`::+--(Required, <<modules-scripting-using,script object>>) Script used to compute the score of documents returned by the `query`.IMPORTANT: Final relevance scores from the `script_score` query cannot benegative. To support certain search optimizations, Lucene requiresscores be positive or `0`.--`min_score`::(Optional, float) Documents with a score lowerthan this floating point number are excluded from the search results.`boost`::(Optional, float) Documents' scores produced by `script` aremultiplied by `boost` to produce final documents' scores. Defaults to `1.0`.[[script-score-query-notes]]==== Notes[[script-score-access-scores]]===== Use relevance scores in a scriptWithin a script, you can{ref}/modules-scripting-fields.html#scripting-score[access] the `_score` variable which represents the current relevance score of adocument.[[script-score-predefined-functions]]===== Predefined functionsYou can use any of the available {painless}/painless-contexts.html[painlessfunctions] in your `script`. You can also use the following predefined functionsto customize scoring:* <<script-score-saturation>>* <<script-score-sigmoid>>* <<random-score-function>>* <<decay-functions-numeric-fields>>* <<decay-functions-geo-fields>>* <<decay-functions-date-fields>>* <<script-score-functions-vector-fields>>We suggest using these predefined functions instead of writing your own.These functions take advantage of efficiencies from {es}' internal mechanisms.[[script-score-saturation]]====== Saturation`saturation(value,k) = value/(k + value)`[source,js]--------------------------------------------------"script" : {    "source" : "saturation(doc['likes'].value, 1)"}--------------------------------------------------// NOTCONSOLE[[script-score-sigmoid]]====== Sigmoid`sigmoid(value, k, a) = value^a/ (k^a + value^a)`[source,js]--------------------------------------------------"script" : {    "source" : "sigmoid(doc['likes'].value, 2, 1)"}--------------------------------------------------// NOTCONSOLE[[random-score-function]]====== Random score function`random_score` function generates scores that are uniformly distributedfrom 0 up to but not including 1.`randomScore` function has the following syntax:`randomScore(<seed>, <fieldName>)`.It has a required parameter - `seed` as an integer value,and an optional parameter - `fieldName` as a string value.[source,js]--------------------------------------------------"script" : {    "source" : "randomScore(100, '_seq_no')"}--------------------------------------------------// NOTCONSOLEIf the `fieldName` parameter is omitted, the internal Lucenedocument ids will be used as a source of randomness. This is very efficient,but unfortunately not reproducible since documents might be renumberedby merges.[source,js]--------------------------------------------------"script" : {    "source" : "randomScore(100)"}--------------------------------------------------// NOTCONSOLENote that documents that are within the same shard and have thesame value for field will get the same score, so it is usually desirableto use a field that has unique values for all documents across a shard.A good default choice might be to use the `_seq_no`field, whose only drawback is that scores will change if the document isupdated since update operations also update the value of the `_seq_no` field.[[decay-functions-numeric-fields]]====== Decay functions for numeric fieldsYou can read more about decay functions {ref}/query-dsl-function-score-query.html#function-decay[here].* `double decayNumericLinear(double origin, double scale, double offset, double decay, double docValue)`* `double decayNumericExp(double origin, double scale, double offset, double decay, double docValue)`* `double decayNumericGauss(double origin, double scale, double offset, double decay, double docValue)`[source,js]--------------------------------------------------"script" : {    "source" : "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['dval'].value)",    "params": { <1>        "origin": 20,        "scale": 10,        "decay" : 0.5,        "offset" : 0    }}--------------------------------------------------// NOTCONSOLE<1> Using `params` allows to compile the script only once, even if params change.[[decay-functions-geo-fields]]====== Decay functions for geo fields* `double decayGeoLinear(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)`* `double decayGeoExp(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)`* `double decayGeoGauss(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)`[source,js]--------------------------------------------------"script" : {    "source" : "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",    "params": {        "origin": "40, -70.12",        "scale": "200km",        "offset": "0km",        "decay" : 0.2    }}--------------------------------------------------// NOTCONSOLE[[decay-functions-date-fields]]====== Decay functions for date fields* `double decayDateLinear(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)`* `double decayDateExp(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)`* `double decayDateGauss(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)`[source,js]--------------------------------------------------"script" : {    "source" : "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",    "params": {        "origin": "2008-01-01T01:00:00Z",        "scale": "1h",        "offset" : "0",        "decay" : 0.5    }}--------------------------------------------------// NOTCONSOLENOTE: Decay functions on dates are limited to dates in the default formatand default time zone. Also calculations with `now` are not supported.[[script-score-functions-vector-fields]]====== Functions for vector fields<<vector-functions, Functions for vector fields>> are accessible through`script_score` query.===== Allow expensive queriesScript score queries will not be executed if <<query-dsl-allow-expensive-queries, `search.allow_expensive_queries`>>is set to false.[[script-score-faster-alt]]===== Faster alternativesThe `script_score` query calculates the score forevery matching document, or hit. There are faster alternative query types thatcan efficiently skip non-competitive hits:* If you want to boost documents on some static fields, use the  <<query-dsl-rank-feature-query, `rank_feature`>> query. * If you want to boost documents closer to a date or geographic point, use the <<query-dsl-distance-feature-query, `distance_feature`>> query.[[script-score-function-score-transition]]===== Transition from the function score queryWe are deprecating the <<query-dsl-function-score-query, `function_score`>>query. We recommend using the `script_score` query instead.You can implement the following functions from the `function_score` query usingthe `script_score` query:* <<script-score>>* <<weight>>* <<random-score>>* <<field-value-factor>>* <<decay-functions>>[[script-score]]====== `script_score`What you used in `script_score` of the Function Score query, youcan copy into the Script Score query. No changes here.[[weight]]====== `weight``weight` function can be implemented in the Script Score query throughthe following script:[source,js]--------------------------------------------------"script" : {    "source" : "params.weight * _score",    "params": {        "weight": 2    }}--------------------------------------------------// NOTCONSOLE[[random-score]]====== `random_score`Use `randomScore` functionas described in <<random-score-function, random score function>>.[[field-value-factor]]====== `field_value_factor``field_value_factor` function can be easily implemented through script:[source,js]--------------------------------------------------"script" : {    "source" : "Math.log10(doc['field'].value * params.factor)",    "params" : {        "factor" : 5    }}--------------------------------------------------// NOTCONSOLEFor checking if a document has a missing value, you can use`doc['field'].size() == 0`. For example, this script will usea value `1` if a document doesn't have a field `field`:[source,js]--------------------------------------------------"script" : {    "source" : "Math.log10((doc['field'].size() == 0 ? 1 : doc['field'].value()) * params.factor)",    "params" : {        "factor" : 5    }}--------------------------------------------------// NOTCONSOLEThis table lists how `field_value_factor` modifiers can be implementedthrough a script:[cols="<,<",options="header",]|=======================================================================| Modifier | Implementation in Script Score| `none` | -| `log` |  `Math.log10(doc['f'].value)`| `log1p` | `Math.log10(doc['f'].value + 1)`| `log2p` | `Math.log10(doc['f'].value + 2)`| `ln` | `Math.log(doc['f'].value)`| `ln1p` | `Math.log(doc['f'].value + 1)`| `ln2p` | `Math.log(doc['f'].value + 2)`| `square` | `Math.pow(doc['f'].value, 2)`| `sqrt` | `Math.sqrt(doc['f'].value)`| `reciprocal` | `1.0 / doc['f'].value`|=======================================================================[[decay-functions]]====== `decay` functionsThe `script_score` query has equivalent <<decay-functions, decay functions>>that can be used in script.include::{es-repo-dir}/vectors/vector-functions.asciidoc[][[score-explanation]]====== Explain requestUsing an <<search-explain, explain request>> provides an explanation of how the parts of a score were computed. The `script_score` query can add its own explanation by setting the `explanation` parameter:[source,console]--------------------------------------------------GET /twitter/_explain/0{  "query": {    "script_score": {      "query": {        "match": { "message": "elasticsearch" }      },      "script": {        "source": """          long likes = doc['likes'].value;          double normalizedLikes = likes / 10;          if (explanation != null) {            explanation.set('normalized likes = likes / 10 = ' + likes + ' / 10 = ' + normalizedLikes);          }          return normalizedLikes;        """      }    }  }}--------------------------------------------------// TEST[setup:twitter]Note that the `explanation` will be null when using in a normal `_search` request, so having a conditional guard is best practice.
 |