vendor/ongr/elasticsearch-dsl/src/Search.php line 223

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the ONGR package.
  4. *
  5. * (c) NFQ Technologies UAB <info@nfq.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace ONGR\ElasticsearchDSL;
  11. use ONGR\ElasticsearchDSL\Aggregation\AbstractAggregation;
  12. use ONGR\ElasticsearchDSL\Highlight\Highlight;
  13. use ONGR\ElasticsearchDSL\InnerHit\NestedInnerHit;
  14. use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery;
  15. use ONGR\ElasticsearchDSL\SearchEndpoint\AbstractSearchEndpoint;
  16. use ONGR\ElasticsearchDSL\SearchEndpoint\AggregationsEndpoint;
  17. use ONGR\ElasticsearchDSL\SearchEndpoint\HighlightEndpoint;
  18. use ONGR\ElasticsearchDSL\SearchEndpoint\InnerHitsEndpoint;
  19. use ONGR\ElasticsearchDSL\SearchEndpoint\PostFilterEndpoint;
  20. use ONGR\ElasticsearchDSL\SearchEndpoint\QueryEndpoint;
  21. use ONGR\ElasticsearchDSL\SearchEndpoint\SearchEndpointFactory;
  22. use ONGR\ElasticsearchDSL\SearchEndpoint\SearchEndpointInterface;
  23. use ONGR\ElasticsearchDSL\SearchEndpoint\SortEndpoint;
  24. use ONGR\ElasticsearchDSL\Serializer\Normalizer\CustomReferencedNormalizer;
  25. use ONGR\ElasticsearchDSL\Serializer\OrderedSerializer;
  26. use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
  27. use ONGR\ElasticsearchDSL\SearchEndpoint\SuggestEndpoint;
  28. /**
  29. * Search object that can be executed by a manager.
  30. */
  31. class Search
  32. {
  33. /**
  34. * If you don’t need to track the total number of hits at all you can improve
  35. * query times by setting this option to false. Defaults to true.
  36. *
  37. * @var bool
  38. */
  39. private $trackTotalHits;
  40. /**
  41. * To retrieve hits from a certain offset. Defaults to 0.
  42. *
  43. * @var int
  44. */
  45. private $from;
  46. /**
  47. * The number of hits to return. Defaults to 10. If you do not care about getting some
  48. * hits back but only about the number of matches and/or aggregations, setting the value
  49. * to 0 will help performance.
  50. *
  51. * @var int
  52. */
  53. private $size;
  54. /**
  55. * Allows to control how the _source field is returned with every hit. By default
  56. * operations return the contents of the _source field unless you have used the
  57. * stored_fields parameter or if the _source field is disabled.
  58. *
  59. * @var bool
  60. */
  61. private $source;
  62. /**
  63. * Allows to selectively load specific stored fields for each document represented by a search hit.
  64. *
  65. * @var array
  66. */
  67. private $storedFields;
  68. /**
  69. * Allows to return a script evaluation (based on different fields) for each hit.
  70. * Script fields can work on fields that are not stored, and allow to return custom
  71. * values to be returned (the evaluated value of the script). Script fields can
  72. * also access the actual _source document indexed and extract specific elements
  73. * to be returned from it (can be an "object" type).
  74. *
  75. * @var array
  76. */
  77. private $scriptFields;
  78. /**
  79. * Allows to return the doc value representation of a field for each hit. Doc value
  80. * fields can work on fields that are not stored. Note that if the fields parameter
  81. * specifies fields without docvalues it will try to load the value from the fielddata
  82. * cache causing the terms for that field to be loaded to memory (cached), which will
  83. * result in more memory consumption.
  84. *
  85. * @var array
  86. */
  87. private $docValueFields;
  88. /**
  89. * Enables explanation for each hit on how its score was computed.
  90. *
  91. * @var bool
  92. */
  93. private $explain;
  94. /**
  95. * Returns a version for each search hit.
  96. *
  97. * @var bool
  98. */
  99. private $version;
  100. /**
  101. * Allows to configure different boost level per index when searching across more
  102. * than one indices. This is very handy when hits coming from one index matter more
  103. * than hits coming from another index (think social graph where each user has an index).
  104. *
  105. * @var array
  106. */
  107. private $indicesBoost;
  108. /**
  109. * Exclude documents which have a _score less than the minimum specified in min_score.
  110. *
  111. * @var int
  112. */
  113. private $minScore;
  114. /**
  115. * Pagination of results can be done by using the from and size but the cost becomes
  116. * prohibitive when the deep pagination is reached. The index.max_result_window which
  117. * defaults to 10,000 is a safeguard, search requests take heap memory and time
  118. * proportional to from + size. The Scroll api is recommended for efficient deep
  119. * scrolling but scroll contexts are costly and it is not recommended to use it for
  120. * real time user requests. The search_after parameter circumvents this problem by
  121. * providing a live cursor. The idea is to use the results from the previous page to
  122. * help the retrieval of the next page.
  123. *
  124. * @var array
  125. */
  126. private $searchAfter;
  127. /**
  128. * URI parameters alongside Request body search.
  129. *
  130. * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
  131. *
  132. * @var array
  133. */
  134. private $uriParams = [];
  135. /**
  136. * While a search request returns a single “page” of results, the scroll API can be used to retrieve
  137. * large numbers of results (or even all results) from a single search request, in much the same way
  138. * as you would use a cursor on a traditional database. Scrolling is not intended for real time user
  139. * requests, but rather for processing large amounts of data, e.g. in order to reindex the contents
  140. * of one index into a new index with a different configuration.
  141. *
  142. * @var string
  143. */
  144. private $scroll;
  145. /**
  146. * @var OrderedSerializer
  147. */
  148. private static $serializer;
  149. /**
  150. * @var SearchEndpointInterface[]
  151. */
  152. private $endpoints = [];
  153. /**
  154. * Constructor to initialize static properties
  155. */
  156. public function __construct()
  157. {
  158. $this->initializeSerializer();
  159. }
  160. /**
  161. * Wakeup method to initialize static properties
  162. */
  163. public function __wakeup()
  164. {
  165. $this->initializeSerializer();
  166. }
  167. /**
  168. * Initializes the serializer
  169. */
  170. private function initializeSerializer()
  171. {
  172. if (static::$serializer === null) {
  173. static::$serializer = new OrderedSerializer(
  174. [
  175. new CustomReferencedNormalizer(),
  176. new CustomNormalizer(),
  177. ]
  178. );
  179. }
  180. }
  181. /**
  182. * Destroys search endpoint.
  183. *
  184. * @param string $type Endpoint type.
  185. */
  186. public function destroyEndpoint($type)
  187. {
  188. unset($this->endpoints[$type]);
  189. }
  190. /**
  191. * Adds query to the search.
  192. *
  193. * @param BuilderInterface $query
  194. * @param string $boolType
  195. * @param string $key
  196. *
  197. * @return $this
  198. */
  199. public function addQuery(BuilderInterface $query, $boolType = BoolQuery::MUST, $key = null)
  200. {
  201. $endpoint = $this->getEndpoint(QueryEndpoint::NAME);
  202. $endpoint->addToBool($query, $boolType, $key);
  203. return $this;
  204. }
  205. /**
  206. * Returns endpoint instance.
  207. *
  208. * @param string $type Endpoint type.
  209. *
  210. * @return SearchEndpointInterface
  211. */
  212. private function getEndpoint($type)
  213. {
  214. if (!array_key_exists($type, $this->endpoints)) {
  215. $this->endpoints[$type] = SearchEndpointFactory::get($type);
  216. }
  217. return $this->endpoints[$type];
  218. }
  219. /**
  220. * Returns queries inside BoolQuery instance.
  221. *
  222. * @return BoolQuery
  223. */
  224. public function getQueries()
  225. {
  226. $endpoint = $this->getEndpoint(QueryEndpoint::NAME);
  227. return $endpoint->getBool();
  228. }
  229. /**
  230. * Sets query endpoint parameters.
  231. *
  232. * @param array $parameters
  233. *
  234. * @return $this
  235. */
  236. public function setQueryParameters(array $parameters)
  237. {
  238. $this->setEndpointParameters(QueryEndpoint::NAME, $parameters);
  239. return $this;
  240. }
  241. /**
  242. * Sets parameters to the endpoint.
  243. *
  244. * @param string $endpointName
  245. * @param array $parameters
  246. *
  247. * @return $this
  248. */
  249. public function setEndpointParameters($endpointName, array $parameters)
  250. {
  251. /** @var AbstractSearchEndpoint $endpoint */
  252. $endpoint = $this->getEndpoint($endpointName);
  253. $endpoint->setParameters($parameters);
  254. return $this;
  255. }
  256. /**
  257. * Adds a post filter to search.
  258. *
  259. * @param BuilderInterface $filter Filter.
  260. * @param string $boolType Example boolType values:
  261. * - must
  262. * - must_not
  263. * - should.
  264. * @param string $key
  265. *
  266. * @return $this.
  267. */
  268. public function addPostFilter(BuilderInterface $filter, $boolType = BoolQuery::MUST, $key = null)
  269. {
  270. $this
  271. ->getEndpoint(PostFilterEndpoint::NAME)
  272. ->addToBool($filter, $boolType, $key);
  273. return $this;
  274. }
  275. /**
  276. * Returns queries inside BoolFilter instance.
  277. *
  278. * @return BoolQuery
  279. */
  280. public function getPostFilters()
  281. {
  282. $endpoint = $this->getEndpoint(PostFilterEndpoint::NAME);
  283. return $endpoint->getBool();
  284. }
  285. /**
  286. * Sets post filter endpoint parameters.
  287. *
  288. * @param array $parameters
  289. *
  290. * @return $this
  291. */
  292. public function setPostFilterParameters(array $parameters)
  293. {
  294. $this->setEndpointParameters(PostFilterEndpoint::NAME, $parameters);
  295. return $this;
  296. }
  297. /**
  298. * Adds aggregation into search.
  299. *
  300. * @param AbstractAggregation $aggregation
  301. *
  302. * @return $this
  303. */
  304. public function addAggregation(AbstractAggregation $aggregation)
  305. {
  306. $this->getEndpoint(AggregationsEndpoint::NAME)->add($aggregation, $aggregation->getName());
  307. return $this;
  308. }
  309. /**
  310. * Returns all aggregations.
  311. *
  312. * @return BuilderInterface[]
  313. */
  314. public function getAggregations()
  315. {
  316. return $this->getEndpoint(AggregationsEndpoint::NAME)->getAll();
  317. }
  318. /**
  319. * Adds inner hit into search.
  320. *
  321. * @param NestedInnerHit $innerHit
  322. *
  323. * @return $this
  324. */
  325. public function addInnerHit(NestedInnerHit $innerHit)
  326. {
  327. $this->getEndpoint(InnerHitsEndpoint::NAME)->add($innerHit, $innerHit->getName());
  328. return $this;
  329. }
  330. /**
  331. * Returns all inner hits.
  332. *
  333. * @return BuilderInterface[]
  334. */
  335. public function getInnerHits()
  336. {
  337. return $this->getEndpoint(InnerHitsEndpoint::NAME)->getAll();
  338. }
  339. /**
  340. * Adds sort to search.
  341. *
  342. * @param BuilderInterface $sort
  343. *
  344. * @return $this
  345. */
  346. public function addSort(BuilderInterface $sort)
  347. {
  348. $this->getEndpoint(SortEndpoint::NAME)->add($sort);
  349. return $this;
  350. }
  351. /**
  352. * Returns all set sorts.
  353. *
  354. * @return BuilderInterface[]
  355. */
  356. public function getSorts()
  357. {
  358. return $this->getEndpoint(SortEndpoint::NAME)->getAll();
  359. }
  360. /**
  361. * Allows to highlight search results on one or more fields.
  362. *
  363. * @param Highlight $highlight
  364. *
  365. * @return $this.
  366. */
  367. public function addHighlight($highlight)
  368. {
  369. $this->getEndpoint(HighlightEndpoint::NAME)->add($highlight);
  370. return $this;
  371. }
  372. /**
  373. * Returns highlight builder.
  374. *
  375. * @return BuilderInterface
  376. */
  377. public function getHighlights()
  378. {
  379. /** @var HighlightEndpoint $highlightEndpoint */
  380. $highlightEndpoint = $this->getEndpoint(HighlightEndpoint::NAME);
  381. return $highlightEndpoint->getHighlight();
  382. }
  383. /**
  384. * Adds suggest into search.
  385. *
  386. * @param BuilderInterface $suggest
  387. *
  388. * @return $this
  389. */
  390. public function addSuggest(NamedBuilderInterface $suggest)
  391. {
  392. $this->getEndpoint(SuggestEndpoint::NAME)->add($suggest, $suggest->getName());
  393. return $this;
  394. }
  395. /**
  396. * Returns all suggests.
  397. *
  398. * @return BuilderInterface[]
  399. */
  400. public function getSuggests()
  401. {
  402. return $this->getEndpoint(SuggestEndpoint::NAME)->getAll();
  403. }
  404. /**
  405. * @return null|int
  406. */
  407. public function getFrom()
  408. {
  409. return $this->from;
  410. }
  411. /**
  412. * @param null|int $from
  413. *
  414. * @return $this
  415. */
  416. public function setFrom($from)
  417. {
  418. $this->from = $from;
  419. return $this;
  420. }
  421. /**
  422. * @return bool
  423. */
  424. public function isTrackTotalHits()
  425. {
  426. return $this->trackTotalHits;
  427. }
  428. /**
  429. * @param bool $trackTotalHits
  430. *
  431. * @return $this
  432. */
  433. public function setTrackTotalHits(bool $trackTotalHits)
  434. {
  435. $this->trackTotalHits = $trackTotalHits;
  436. return $this;
  437. }
  438. /**
  439. * @return null|int
  440. */
  441. public function getSize()
  442. {
  443. return $this->size;
  444. }
  445. /**
  446. * @param null|int $size
  447. *
  448. * @return $this
  449. */
  450. public function setSize($size)
  451. {
  452. $this->size = $size;
  453. return $this;
  454. }
  455. /**
  456. * @return bool
  457. */
  458. public function isSource()
  459. {
  460. return $this->source;
  461. }
  462. /**
  463. * @param bool $source
  464. *
  465. * @return $this
  466. */
  467. public function setSource($source)
  468. {
  469. $this->source = $source;
  470. return $this;
  471. }
  472. /**
  473. * @return array
  474. */
  475. public function getStoredFields()
  476. {
  477. return $this->storedFields;
  478. }
  479. /**
  480. * @param array $storedFields
  481. *
  482. * @return $this
  483. */
  484. public function setStoredFields($storedFields)
  485. {
  486. $this->storedFields = $storedFields;
  487. return $this;
  488. }
  489. /**
  490. * @return array
  491. */
  492. public function getScriptFields()
  493. {
  494. return $this->scriptFields;
  495. }
  496. /**
  497. * @param array $scriptFields
  498. *
  499. * @return $this
  500. */
  501. public function setScriptFields($scriptFields)
  502. {
  503. $this->scriptFields = $scriptFields;
  504. return $this;
  505. }
  506. /**
  507. * @return array
  508. */
  509. public function getDocValueFields()
  510. {
  511. return $this->docValueFields;
  512. }
  513. /**
  514. * @param array $docValueFields
  515. *
  516. * @return $this
  517. */
  518. public function setDocValueFields($docValueFields)
  519. {
  520. $this->docValueFields = $docValueFields;
  521. return $this;
  522. }
  523. /**
  524. * @return bool
  525. */
  526. public function isExplain()
  527. {
  528. return $this->explain;
  529. }
  530. /**
  531. * @param bool $explain
  532. *
  533. * @return $this
  534. */
  535. public function setExplain($explain)
  536. {
  537. $this->explain = $explain;
  538. return $this;
  539. }
  540. /**
  541. * @return bool
  542. */
  543. public function isVersion()
  544. {
  545. return $this->version;
  546. }
  547. /**
  548. * @param bool $version
  549. *
  550. * @return $this
  551. */
  552. public function setVersion($version)
  553. {
  554. $this->version = $version;
  555. return $this;
  556. }
  557. /**
  558. * @return array
  559. */
  560. public function getIndicesBoost()
  561. {
  562. return $this->indicesBoost;
  563. }
  564. /**
  565. * @param array $indicesBoost
  566. *
  567. * @return $this
  568. */
  569. public function setIndicesBoost($indicesBoost)
  570. {
  571. $this->indicesBoost = $indicesBoost;
  572. return $this;
  573. }
  574. /**
  575. * @return int
  576. */
  577. public function getMinScore()
  578. {
  579. return $this->minScore;
  580. }
  581. /**
  582. * @param int $minScore
  583. *
  584. * @return $this
  585. */
  586. public function setMinScore($minScore)
  587. {
  588. $this->minScore = $minScore;
  589. return $this;
  590. }
  591. /**
  592. * @return array
  593. */
  594. public function getSearchAfter()
  595. {
  596. return $this->searchAfter;
  597. }
  598. /**
  599. * @param array $searchAfter
  600. *
  601. * @return $this
  602. */
  603. public function setSearchAfter($searchAfter)
  604. {
  605. $this->searchAfter = $searchAfter;
  606. return $this;
  607. }
  608. /**
  609. * @return string
  610. */
  611. public function getScroll()
  612. {
  613. return $this->scroll;
  614. }
  615. /**
  616. * @param string $scroll
  617. *
  618. * @return $this
  619. */
  620. public function setScroll($scroll = '5m')
  621. {
  622. $this->scroll = $scroll;
  623. $this->addUriParam('scroll', $this->scroll);
  624. return $this;
  625. }
  626. /**
  627. * @param string $name
  628. * @param string|array|bool $value
  629. *
  630. * @return $this
  631. */
  632. public function addUriParam($name, $value)
  633. {
  634. if (in_array($name, [
  635. 'q',
  636. 'df',
  637. 'analyzer',
  638. 'analyze_wildcard',
  639. 'default_operator',
  640. 'lenient',
  641. 'explain',
  642. '_source',
  643. '_source_exclude',
  644. '_source_include',
  645. 'stored_fields',
  646. 'sort',
  647. 'track_scores',
  648. 'timeout',
  649. 'terminate_after',
  650. 'from',
  651. 'size',
  652. 'search_type',
  653. 'scroll',
  654. 'allow_no_indices',
  655. 'ignore_unavailable',
  656. 'typed_keys',
  657. 'pre_filter_shard_size',
  658. 'ignore_unavailable',
  659. ])) {
  660. $this->uriParams[$name] = $value;
  661. } else {
  662. throw new \InvalidArgumentException(sprintf('Parameter %s is not supported.', $value));
  663. }
  664. return $this;
  665. }
  666. /**
  667. * Returns query url parameters.
  668. *
  669. * @return array
  670. */
  671. public function getUriParams()
  672. {
  673. return $this->uriParams;
  674. }
  675. /**
  676. * {@inheritdoc}
  677. */
  678. public function toArray()
  679. {
  680. $output = array_filter(static::$serializer->normalize($this->endpoints));
  681. $params = [
  682. 'from' => 'from',
  683. 'size' => 'size',
  684. 'source' => '_source',
  685. 'storedFields' => 'stored_fields',
  686. 'scriptFields' => 'script_fields',
  687. 'docValueFields' => 'docvalue_fields',
  688. 'explain' => 'explain',
  689. 'version' => 'version',
  690. 'indicesBoost' => 'indices_boost',
  691. 'minScore' => 'min_score',
  692. 'searchAfter' => 'search_after',
  693. 'trackTotalHits' => 'track_total_hits',
  694. ];
  695. foreach ($params as $field => $param) {
  696. if ($this->$field !== null) {
  697. $output[$param] = $this->$field;
  698. }
  699. }
  700. return $output;
  701. }
  702. }