vendor/ruflin/elastica/lib/Elastica/Search.php line 460

Open in your IDE?
  1. <?php
  2. namespace Elastica;
  3. use Elastica\Exception\InvalidException;
  4. use Elastica\ResultSet\BuilderInterface;
  5. use Elastica\ResultSet\DefaultBuilder;
  6. /**
  7.  * Elastica search object.
  8.  *
  9.  * @author   Nicolas Ruflin <spam@ruflin.com>
  10.  */
  11. class Search
  12. {
  13.     /*
  14.      * Options
  15.      */
  16.     const OPTION_SEARCH_TYPE 'search_type';
  17.     const OPTION_ROUTING 'routing';
  18.     const OPTION_PREFERENCE 'preference';
  19.     const OPTION_VERSION 'version';
  20.     const OPTION_TIMEOUT 'timeout';
  21.     const OPTION_FROM 'from';
  22.     const OPTION_SIZE 'size';
  23.     const OPTION_SCROLL 'scroll';
  24.     const OPTION_SCROLL_ID 'scroll_id';
  25.     const OPTION_QUERY_CACHE 'query_cache';
  26.     const OPTION_TERMINATE_AFTER 'terminate_after';
  27.     const OPTION_SHARD_REQUEST_CACHE 'request_cache';
  28.     const OPTION_FILTER_PATH 'filter_path';
  29.     /*
  30.      * Search types
  31.      */
  32.     const OPTION_SEARCH_TYPE_DFS_QUERY_THEN_FETCH 'dfs_query_then_fetch';
  33.     const OPTION_SEARCH_TYPE_QUERY_THEN_FETCH 'query_then_fetch';
  34.     const OPTION_SEARCH_TYPE_SUGGEST 'suggest';
  35.     const OPTION_SEARCH_IGNORE_UNAVAILABLE 'ignore_unavailable';
  36.     /**
  37.      * @var BuilderInterface
  38.      */
  39.     private $_builder;
  40.     /**
  41.      * Array of indices.
  42.      *
  43.      * @var array
  44.      */
  45.     protected $_indices = [];
  46.     /**
  47.      * Array of types.
  48.      *
  49.      * @var array
  50.      */
  51.     protected $_types = [];
  52.     /**
  53.      * @var \Elastica\Query
  54.      */
  55.     protected $_query;
  56.     /**
  57.      * @var array
  58.      */
  59.     protected $_options = [];
  60.     /**
  61.      * Client object.
  62.      *
  63.      * @var \Elastica\Client
  64.      */
  65.     protected $_client;
  66.     /**
  67.      * Constructs search object.
  68.      *
  69.      * @param \Elastica\Client $client  Client object
  70.      * @param BuilderInterface $builder
  71.      */
  72.     public function __construct(Client $clientBuilderInterface $builder null)
  73.     {
  74.         $this->_builder $builder ?: new DefaultBuilder();
  75.         $this->_client $client;
  76.     }
  77.     /**
  78.      * Adds a index to the list.
  79.      *
  80.      * @param \Elastica\Index|string $index Index object or string
  81.      *
  82.      * @throws \Elastica\Exception\InvalidException
  83.      *
  84.      * @return $this
  85.      */
  86.     public function addIndex($index)
  87.     {
  88.         if ($index instanceof Index) {
  89.             $index $index->getName();
  90.         }
  91.         if (!is_scalar($index)) {
  92.             throw new InvalidException('Invalid param type');
  93.         }
  94.         $this->_indices[] = (string) $index;
  95.         return $this;
  96.     }
  97.     /**
  98.      * Add array of indices at once.
  99.      *
  100.      * @param array $indices
  101.      *
  102.      * @return $this
  103.      */
  104.     public function addIndices(array $indices = [])
  105.     {
  106.         foreach ($indices as $index) {
  107.             $this->addIndex($index);
  108.         }
  109.         return $this;
  110.     }
  111.     /**
  112.      * Adds a type to the current search.
  113.      *
  114.      * @param \Elastica\Type|string $type Type name or object
  115.      *
  116.      * @throws \Elastica\Exception\InvalidException
  117.      *
  118.      * @return $this
  119.      */
  120.     public function addType($type)
  121.     {
  122.         if ($type instanceof Type) {
  123.             $type $type->getName();
  124.         }
  125.         if (!is_string($type)) {
  126.             throw new InvalidException('Invalid type type');
  127.         }
  128.         $this->_types[] = $type;
  129.         return $this;
  130.     }
  131.     /**
  132.      * Add array of types.
  133.      *
  134.      * @param array $types
  135.      *
  136.      * @return $this
  137.      */
  138.     public function addTypes(array $types = [])
  139.     {
  140.         foreach ($types as $type) {
  141.             $this->addType($type);
  142.         }
  143.         return $this;
  144.     }
  145.     /**
  146.      * @param string|array|\Elastica\Query|\Elastica\Suggest|\Elastica\Query\AbstractQuery $query
  147.      *
  148.      * @return $this
  149.      */
  150.     public function setQuery($query)
  151.     {
  152.         $this->_query Query::create($query);
  153.         return $this;
  154.     }
  155.     /**
  156.      * @param string $key
  157.      * @param mixed  $value
  158.      *
  159.      * @return $this
  160.      */
  161.     public function setOption($key$value)
  162.     {
  163.         $this->_validateOption($key);
  164.         $this->_options[$key] = $value;
  165.         return $this;
  166.     }
  167.     /**
  168.      * @param array $options
  169.      *
  170.      * @return $this
  171.      */
  172.     public function setOptions(array $options)
  173.     {
  174.         $this->clearOptions();
  175.         foreach ($options as $key => $value) {
  176.             $this->setOption($key$value);
  177.         }
  178.         return $this;
  179.     }
  180.     /**
  181.      * @return $this
  182.      */
  183.     public function clearOptions()
  184.     {
  185.         $this->_options = [];
  186.         return $this;
  187.     }
  188.     /**
  189.      * @param string $key
  190.      * @param mixed  $value
  191.      *
  192.      * @return $this
  193.      */
  194.     public function addOption($key$value)
  195.     {
  196.         $this->_validateOption($key);
  197.         $this->_options[$key][] = $value;
  198.         return $this;
  199.     }
  200.     /**
  201.      * @param string $key
  202.      *
  203.      * @return bool
  204.      */
  205.     public function hasOption($key)
  206.     {
  207.         return isset($this->_options[$key]);
  208.     }
  209.     /**
  210.      * @param string $key
  211.      *
  212.      * @throws \Elastica\Exception\InvalidException
  213.      *
  214.      * @return mixed
  215.      */
  216.     public function getOption($key)
  217.     {
  218.         if (!$this->hasOption($key)) {
  219.             throw new InvalidException('Option '.$key.' does not exist');
  220.         }
  221.         return $this->_options[$key];
  222.     }
  223.     /**
  224.      * @return array
  225.      */
  226.     public function getOptions()
  227.     {
  228.         return $this->_options;
  229.     }
  230.     /**
  231.      * @param string $key
  232.      *
  233.      * @throws \Elastica\Exception\InvalidException
  234.      *
  235.      * @return bool
  236.      */
  237.     protected function _validateOption($key)
  238.     {
  239.         switch ($key) {
  240.             case self::OPTION_SEARCH_TYPE:
  241.             case self::OPTION_ROUTING:
  242.             case self::OPTION_PREFERENCE:
  243.             case self::OPTION_VERSION:
  244.             case self::OPTION_TIMEOUT:
  245.             case self::OPTION_FROM:
  246.             case self::OPTION_SIZE:
  247.             case self::OPTION_SCROLL:
  248.             case self::OPTION_SCROLL_ID:
  249.             case self::OPTION_SEARCH_TYPE_SUGGEST:
  250.             case self::OPTION_SEARCH_IGNORE_UNAVAILABLE:
  251.             case self::OPTION_QUERY_CACHE:
  252.             case self::OPTION_TERMINATE_AFTER:
  253.             case self::OPTION_SHARD_REQUEST_CACHE:
  254.             case self::OPTION_FILTER_PATH:
  255.                 return true;
  256.         }
  257.         throw new InvalidException('Invalid option '.$key);
  258.     }
  259.     /**
  260.      * Return client object.
  261.      *
  262.      * @return \Elastica\Client Client object
  263.      */
  264.     public function getClient()
  265.     {
  266.         return $this->_client;
  267.     }
  268.     /**
  269.      * Return array of indices.
  270.      *
  271.      * @return array List of index names
  272.      */
  273.     public function getIndices()
  274.     {
  275.         return $this->_indices;
  276.     }
  277.     /**
  278.      * @return bool
  279.      */
  280.     public function hasIndices()
  281.     {
  282.         return count($this->_indices) > 0;
  283.     }
  284.     /**
  285.      * @param Index|string $index
  286.      *
  287.      * @return bool
  288.      */
  289.     public function hasIndex($index)
  290.     {
  291.         if ($index instanceof Index) {
  292.             $index $index->getName();
  293.         }
  294.         return in_array($index$this->_indices);
  295.     }
  296.     /**
  297.      * Return array of types.
  298.      *
  299.      * @return array List of types
  300.      */
  301.     public function getTypes()
  302.     {
  303.         return $this->_types;
  304.     }
  305.     /**
  306.      * @return bool
  307.      */
  308.     public function hasTypes()
  309.     {
  310.         return count($this->_types) > 0;
  311.     }
  312.     /**
  313.      * @param \Elastica\Type|string $type
  314.      *
  315.      * @return bool
  316.      */
  317.     public function hasType($type)
  318.     {
  319.         if ($type instanceof Type) {
  320.             $type $type->getName();
  321.         }
  322.         return in_array($type$this->_types);
  323.     }
  324.     /**
  325.      * @return \Elastica\Query
  326.      */
  327.     public function getQuery()
  328.     {
  329.         if (null === $this->_query) {
  330.             $this->_query Query::create('');
  331.         }
  332.         return $this->_query;
  333.     }
  334.     /**
  335.      * Creates new search object.
  336.      *
  337.      * @param \Elastica\SearchableInterface $searchObject
  338.      *
  339.      * @return Search
  340.      */
  341.     public static function create(SearchableInterface $searchObject)
  342.     {
  343.         return $searchObject->createSearch();
  344.     }
  345.     /**
  346.      * Combines indices and types to the search request path.
  347.      *
  348.      * @return string Search path
  349.      */
  350.     public function getPath()
  351.     {
  352.         if (isset($this->_options[self::OPTION_SCROLL_ID])) {
  353.             return '_search/scroll';
  354.         }
  355.         $indices $this->getIndices();
  356.         $path '';
  357.         $types $this->getTypes();
  358.         if (empty($indices)) {
  359.             if (!empty($types)) {
  360.                 $path .= '_all';
  361.             }
  362.         } else {
  363.             $path .= implode(','$indices);
  364.         }
  365.         if (!empty($types)) {
  366.             $path .= '/'.implode(','$types);
  367.         }
  368.         // Add full path based on indices and types -> could be all
  369.         return $path.'/_search';
  370.     }
  371.     /**
  372.      * Search in the set indices, types.
  373.      *
  374.      * @param mixed     $query
  375.      * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
  376.      *
  377.      * @throws \Elastica\Exception\InvalidException
  378.      *
  379.      * @return \Elastica\ResultSet
  380.      */
  381.     public function search($query ''$options null)
  382.     {
  383.         $this->setOptionsAndQuery($options$query);
  384.         $query $this->getQuery();
  385.         $path $this->getPath();
  386.         $params $this->getOptions();
  387.         // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
  388.         if ('_search/scroll' == $path) {
  389.             $data = [self::OPTION_SCROLL_ID => $params[self::OPTION_SCROLL_ID]];
  390.             unset($params[self::OPTION_SCROLL_ID]);
  391.         } else {
  392.             $data $query->toArray();
  393.         }
  394.         $response $this->getClient()->request(
  395.             $path,
  396.             Request::GET,
  397.             $data,
  398.             $params
  399.         );
  400.         return $this->_builder->buildResultSet($response$query);
  401.     }
  402.     /**
  403.      * @param mixed $query
  404.      * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including aggregations is returned
  405.      *
  406.      * @return int|ResultSet
  407.      */
  408.     public function count($query ''$fullResult false)
  409.     {
  410.         $this->setOptionsAndQuery(null$query);
  411.         // Clone the object as we do not want to modify the original query.
  412.         $query = clone $this->getQuery();
  413.         $query->setSize(0);
  414.         $path $this->getPath();
  415.         $response $this->getClient()->request(
  416.             $path,
  417.             Request::GET,
  418.             $query->toArray(),
  419.             [self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_QUERY_THEN_FETCH]
  420.         );
  421.         $resultSet $this->_builder->buildResultSet($response$query);
  422.         return $fullResult $resultSet $resultSet->getTotalHits();
  423.     }
  424.     /**
  425.      * @param array|int                    $options
  426.      * @param string|array|\Elastica\Query $query
  427.      *
  428.      * @return $this
  429.      */
  430.     public function setOptionsAndQuery($options null$query '')
  431.     {
  432.         if ('' != $query) {
  433.             $this->setQuery($query);
  434.         }
  435.         if (is_int($options)) {
  436.             $this->getQuery()->setSize($options);
  437.         } elseif (is_array($options)) {
  438.             if (isset($options['limit'])) {
  439.                 $this->getQuery()->setSize($options['limit']);
  440.                 unset($options['limit']);
  441.             }
  442.             if (isset($options['explain'])) {
  443.                 $this->getQuery()->setExplain($options['explain']);
  444.                 unset($options['explain']);
  445.             }
  446.             $this->setOptions($options);
  447.         }
  448.         return $this;
  449.     }
  450.     /**
  451.      * @param Suggest $suggest
  452.      *
  453.      * @return $this
  454.      */
  455.     public function setSuggest(Suggest $suggest)
  456.     {
  457.         return $this->setOptionsAndQuery([self::OPTION_SEARCH_TYPE_SUGGEST => 'suggest'], $suggest);
  458.     }
  459.     /**
  460.      * Returns the Scroll Iterator.
  461.      *
  462.      * @see Elastica\Scroll
  463.      *
  464.      * @param string $expiryTime
  465.      *
  466.      * @return Scroll
  467.      */
  468.     public function scroll($expiryTime '1m')
  469.     {
  470.         return new Scroll($this$expiryTime);
  471.     }
  472.     /**
  473.      * @return BuilderInterface
  474.      */
  475.     public function getResultSetBuilder()
  476.     {
  477.         return $this->_builder;
  478.     }
  479. }