1<?php 2 3namespace Elastica\Query; 4 5use Elastica\Script\AbstractScript; 6 7/** 8 * Class FunctionScore. 9 * 10 * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html 11 */ 12class FunctionScore extends AbstractQuery 13{ 14 public const BOOST_MODE_MULTIPLY = 'multiply'; 15 public const BOOST_MODE_REPLACE = 'replace'; 16 public const BOOST_MODE_SUM = 'sum'; 17 public const BOOST_MODE_AVERAGE = 'avg'; 18 public const BOOST_MODE_MAX = 'max'; 19 public const BOOST_MODE_MIN = 'min'; 20 21 public const SCORE_MODE_MULTIPLY = 'multiply'; 22 public const SCORE_MODE_SUM = 'sum'; 23 public const SCORE_MODE_AVERAGE = 'avg'; 24 public const SCORE_MODE_FIRST = 'first'; 25 public const SCORE_MODE_MAX = 'max'; 26 public const SCORE_MODE_MIN = 'min'; 27 28 public const DECAY_GAUSS = 'gauss'; 29 public const DECAY_EXPONENTIAL = 'exp'; 30 public const DECAY_LINEAR = 'linear'; 31 32 public const FIELD_VALUE_FACTOR_MODIFIER_NONE = 'none'; 33 public const FIELD_VALUE_FACTOR_MODIFIER_LOG = 'log'; 34 public const FIELD_VALUE_FACTOR_MODIFIER_LOG1P = 'log1p'; 35 public const FIELD_VALUE_FACTOR_MODIFIER_LOG2P = 'log2p'; 36 public const FIELD_VALUE_FACTOR_MODIFIER_LN = 'ln'; 37 public const FIELD_VALUE_FACTOR_MODIFIER_LN1P = 'ln1p'; 38 public const FIELD_VALUE_FACTOR_MODIFIER_LN2P = 'ln2p'; 39 public const FIELD_VALUE_FACTOR_MODIFIER_SQUARE = 'square'; 40 public const FIELD_VALUE_FACTOR_MODIFIER_SQRT = 'sqrt'; 41 public const FIELD_VALUE_FACTOR_MODIFIER_RECIPROCAL = 'reciprocal'; 42 43 public const MULTI_VALUE_MODE_MIN = 'min'; 44 public const MULTI_VALUE_MODE_MAX = 'max'; 45 public const MULTI_VALUE_MODE_AVG = 'avg'; 46 public const MULTI_VALUE_MODE_SUM = 'sum'; 47 48 public const RANDOM_SCORE_FIELD_ID = '_id'; 49 public const RANDOM_SCORE_FIELD_SEQ_NO = '_seq_no'; 50 51 protected $_functions = []; 52 53 /** 54 * Set the child query for this function_score query. 55 * 56 * @return $this 57 */ 58 public function setQuery(AbstractQuery $query): self 59 { 60 return $this->setParam('query', $query); 61 } 62 63 /** 64 * Add a function to the function_score query. 65 * 66 * @param string $functionType valid values are DECAY_* constants and script_score 67 * @param AbstractScript|array|float $functionParams the body of the function. See documentation for proper syntax. 68 * @param AbstractQuery|null $filter filter to apply to the function 69 * @param float|null $weight function weight 70 * 71 * @return $this 72 */ 73 public function addFunction( 74 string $functionType, 75 $functionParams, 76 ?AbstractQuery $filter = null, 77 ?float $weight = null 78 ): self { 79 $function = [ 80 $functionType => $functionParams, 81 ]; 82 83 if (null !== $filter) { 84 $function['filter'] = $filter; 85 } 86 87 if (null !== $weight) { 88 $function['weight'] = $weight; 89 } 90 91 $this->_functions[] = $function; 92 93 return $this; 94 } 95 96 /** 97 * Add a script_score function to the query. 98 * 99 * @param AbstractScript $script a Script object 100 * @param AbstractQuery|null $filter an optional filter to apply to the function 101 * @param float|null $weight the weight of the function 102 * 103 * @return $this 104 */ 105 public function addScriptScoreFunction(AbstractScript $script, ?AbstractQuery $filter = null, ?float $weight = null) 106 { 107 return $this->addFunction('script_score', $script, $filter, $weight); 108 } 109 110 /** 111 * Add a decay function to the query. 112 * 113 * TODO: Change "$origin" and "$scale" parameter types to allow "float|int|string". 114 * 115 * @param string $function see DECAY_* constants for valid options 116 * @param string $field the document field on which to perform the decay function 117 * @param string $origin the origin value for this decay function 118 * @param string $scale a scale to define the rate of decay for this function 119 * @param string|null $offset If defined, this function will only be computed for documents with a distance from the origin greater than this value 120 * @param float|null $decay optionally defines how documents are scored at the distance given by the $scale parameter 121 * @param float|null $weight optional factor by which to multiply the score at the value provided by the $scale parameter 122 * @param AbstractQuery|null $filter a filter associated with this function 123 * @param string|null $multiValueMode see MULTI_VALUE_MODE_* constants for valid options 124 * 125 * @return $this 126 */ 127 public function addDecayFunction( 128 string $function, 129 string $field, 130 string $origin, 131 string $scale, 132 ?string $offset = null, 133 ?float $decay = null, 134 ?float $weight = null, 135 ?AbstractQuery $filter = null, 136 ?string $multiValueMode = null 137 ) { 138 $functionParams = [ 139 $field => [ 140 'origin' => $origin, 141 'scale' => $scale, 142 ], 143 ]; 144 if (null !== $offset) { 145 $functionParams[$field]['offset'] = $offset; 146 } 147 if (null !== $decay) { 148 $functionParams[$field]['decay'] = $decay; 149 } 150 151 if (null !== $multiValueMode) { 152 $functionParams['multi_value_mode'] = $multiValueMode; 153 } 154 155 return $this->addFunction($function, $functionParams, $filter, $weight); 156 } 157 158 /** 159 * @return $this 160 */ 161 public function addFieldValueFactorFunction( 162 string $field, 163 ?float $factor = null, 164 ?string $modifier = null, 165 ?float $missing = null, 166 ?float $weight = null, 167 ?AbstractQuery $filter = null 168 ): self { 169 $functionParams = [ 170 'field' => $field, 171 ]; 172 173 if (null !== $factor) { 174 $functionParams['factor'] = $factor; 175 } 176 177 if (null !== $modifier) { 178 $functionParams['modifier'] = $modifier; 179 } 180 181 if (null !== $missing) { 182 $functionParams['missing'] = $missing; 183 } 184 185 return $this->addFunction('field_value_factor', $functionParams, $filter, $weight); 186 } 187 188 /** 189 * @param float $weight the weight of the function 190 * @param AbstractQuery|null $filter a filter associated with this function 191 * 192 * @return $this 193 */ 194 public function addWeightFunction(float $weight, ?AbstractQuery $filter = null): self 195 { 196 return $this->addFunction('weight', $weight, $filter); 197 } 198 199 /** 200 * Add a random_score function to the query. 201 * 202 * @param int $seed the seed value 203 * @param AbstractQuery|null $filter a filter associated with this function 204 * @param float|null $weight an optional boost value associated with this function 205 * @param string|null $field the field to be used for random number generation 206 * 207 * @return $this 208 */ 209 public function addRandomScoreFunction( 210 int $seed, 211 ?AbstractQuery $filter = null, 212 ?float $weight = null, 213 ?string $field = null 214 ): self { 215 $functionParams = [ 216 'seed' => $seed, 217 ]; 218 219 if (null !== $field) { 220 $functionParams['field'] = $field; 221 } 222 223 return $this->addFunction('random_score', $functionParams, $filter, $weight); 224 } 225 226 /** 227 * Set an overall boost value for this query. 228 * 229 * @return $this 230 */ 231 public function setBoost(float $boost): self 232 { 233 return $this->setParam('boost', $boost); 234 } 235 236 /** 237 * Restrict the combined boost of the function_score query and its child query. 238 * 239 * @return $this 240 */ 241 public function setMaxBoost(float $maxBoost): self 242 { 243 return $this->setParam('max_boost', $maxBoost); 244 } 245 246 /** 247 * The boost mode determines how the score of this query is combined with that of the child query. 248 * 249 * @param string $mode see BOOST_MODE_* constants for valid options. Default is multiply. 250 * 251 * @return $this 252 */ 253 public function setBoostMode(string $mode = self::BOOST_MODE_MULTIPLY): self 254 { 255 return $this->setParam('boost_mode', $mode); 256 } 257 258 /** 259 * If set, this query will return results in random order. 260 * 261 * @param int|null $seed set a seed value to return results in the same random order for consistent pagination 262 * 263 * @return $this 264 */ 265 public function setRandomScore(?int $seed = null): self 266 { 267 $seedParam = new \stdClass(); 268 if (null !== $seed) { 269 $seedParam->seed = $seed; 270 } 271 272 return $this->setParam('random_score', $seedParam); 273 } 274 275 /** 276 * Set the score method. 277 * 278 * @param string $mode see SCORE_MODE_* constants for valid options. Default is multiply. 279 * 280 * @return $this 281 */ 282 public function setScoreMode(string $mode = self::SCORE_MODE_MULTIPLY): self 283 { 284 return $this->setParam('score_mode', $mode); 285 } 286 287 /** 288 * Set min_score option. 289 * 290 * @return $this 291 */ 292 public function setMinScore(float $minScore): self 293 { 294 return $this->setParam('min_score', $minScore); 295 } 296 297 /** 298 * {@inheritdoc} 299 */ 300 public function toArray(): array 301 { 302 if (0 < \count($this->_functions)) { 303 $this->setParam('functions', $this->_functions); 304 } 305 306 return parent::toArray(); 307 } 308} 309