| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- <?php
- namespace Elastica;
- use Elastica\Exception\InvalidException;
- use Elastica\ResultSet\BuilderInterface;
- use Elastica\ResultSet\DefaultBuilder;
- /**
- * Elastica search object.
- *
- * @author Nicolas Ruflin <spam@ruflin.com>
- */
- class Search
- {
- /*
- * Options
- */
- const OPTION_SEARCH_TYPE = 'search_type';
- const OPTION_ROUTING = 'routing';
- const OPTION_PREFERENCE = 'preference';
- const OPTION_VERSION = 'version';
- const OPTION_TIMEOUT = 'timeout';
- const OPTION_FROM = 'from';
- const OPTION_SIZE = 'size';
- const OPTION_SCROLL = 'scroll';
- const OPTION_SCROLL_ID = 'scroll_id';
- const OPTION_QUERY_CACHE = 'query_cache';
- const OPTION_TERMINATE_AFTER = 'terminate_after';
- const OPTION_SHARD_REQUEST_CACHE = 'request_cache';
- const OPTION_FILTER_PATH = 'filter_path';
- /*
- * Search types
- */
- const OPTION_SEARCH_TYPE_DFS_QUERY_THEN_FETCH = 'dfs_query_then_fetch';
- const OPTION_SEARCH_TYPE_QUERY_THEN_FETCH = 'query_then_fetch';
- const OPTION_SEARCH_TYPE_SUGGEST = 'suggest';
- const OPTION_SEARCH_IGNORE_UNAVAILABLE = 'ignore_unavailable';
- /**
- * @var BuilderInterface
- */
- private $_builder;
- /**
- * Array of indices.
- *
- * @var array
- */
- protected $_indices = [];
- /**
- * Array of types.
- *
- * @var array
- */
- protected $_types = [];
- /**
- * @var \Elastica\Query
- */
- protected $_query;
- /**
- * @var array
- */
- protected $_options = [];
- /**
- * Client object.
- *
- * @var \Elastica\Client
- */
- protected $_client;
- /**
- * Constructs search object.
- *
- * @param \Elastica\Client $client Client object
- * @param BuilderInterface $builder
- */
- public function __construct(Client $client, BuilderInterface $builder = null)
- {
- $this->_builder = $builder ?: new DefaultBuilder();
- $this->_client = $client;
- }
- /**
- * Adds a index to the list.
- *
- * @param \Elastica\Index|string $index Index object or string
- *
- * @throws \Elastica\Exception\InvalidException
- *
- * @return $this
- */
- public function addIndex($index)
- {
- if ($index instanceof Index) {
- $index = $index->getName();
- }
- if (!is_scalar($index)) {
- throw new InvalidException('Invalid param type');
- }
- $this->_indices[] = (string) $index;
- return $this;
- }
- /**
- * Add array of indices at once.
- *
- * @param array $indices
- *
- * @return $this
- */
- public function addIndices(array $indices = [])
- {
- foreach ($indices as $index) {
- $this->addIndex($index);
- }
- return $this;
- }
- /**
- * Adds a type to the current search.
- *
- * @param \Elastica\Type|string $type Type name or object
- *
- * @throws \Elastica\Exception\InvalidException
- *
- * @return $this
- */
- public function addType($type)
- {
- if ($type instanceof Type) {
- $type = $type->getName();
- }
- if (!is_string($type)) {
- throw new InvalidException('Invalid type type');
- }
- $this->_types[] = $type;
- return $this;
- }
- /**
- * Add array of types.
- *
- * @param array $types
- *
- * @return $this
- */
- public function addTypes(array $types = [])
- {
- foreach ($types as $type) {
- $this->addType($type);
- }
- return $this;
- }
- /**
- * @param string|array|\Elastica\Query|\Elastica\Suggest|\Elastica\Query\AbstractQuery $query
- *
- * @return $this
- */
- public function setQuery($query)
- {
- $this->_query = Query::create($query);
- return $this;
- }
- /**
- * @param string $key
- * @param mixed $value
- *
- * @return $this
- */
- public function setOption($key, $value)
- {
- $this->_validateOption($key);
- $this->_options[$key] = $value;
- return $this;
- }
- /**
- * @param array $options
- *
- * @return $this
- */
- public function setOptions(array $options)
- {
- $this->clearOptions();
- foreach ($options as $key => $value) {
- $this->setOption($key, $value);
- }
- return $this;
- }
- /**
- * @return $this
- */
- public function clearOptions()
- {
- $this->_options = [];
- return $this;
- }
- /**
- * @param string $key
- * @param mixed $value
- *
- * @return $this
- */
- public function addOption($key, $value)
- {
- $this->_validateOption($key);
- $this->_options[$key][] = $value;
- return $this;
- }
- /**
- * @param string $key
- *
- * @return bool
- */
- public function hasOption($key)
- {
- return isset($this->_options[$key]);
- }
- /**
- * @param string $key
- *
- * @throws \Elastica\Exception\InvalidException
- *
- * @return mixed
- */
- public function getOption($key)
- {
- if (!$this->hasOption($key)) {
- throw new InvalidException('Option '.$key.' does not exist');
- }
- return $this->_options[$key];
- }
- /**
- * @return array
- */
- public function getOptions()
- {
- return $this->_options;
- }
- /**
- * @param string $key
- *
- * @throws \Elastica\Exception\InvalidException
- *
- * @return bool
- */
- protected function _validateOption($key)
- {
- switch ($key) {
- case self::OPTION_SEARCH_TYPE:
- case self::OPTION_ROUTING:
- case self::OPTION_PREFERENCE:
- case self::OPTION_VERSION:
- case self::OPTION_TIMEOUT:
- case self::OPTION_FROM:
- case self::OPTION_SIZE:
- case self::OPTION_SCROLL:
- case self::OPTION_SCROLL_ID:
- case self::OPTION_SEARCH_TYPE_SUGGEST:
- case self::OPTION_SEARCH_IGNORE_UNAVAILABLE:
- case self::OPTION_QUERY_CACHE:
- case self::OPTION_TERMINATE_AFTER:
- case self::OPTION_SHARD_REQUEST_CACHE:
- case self::OPTION_FILTER_PATH:
- return true;
- }
- throw new InvalidException('Invalid option '.$key);
- }
- /**
- * Return client object.
- *
- * @return \Elastica\Client Client object
- */
- public function getClient()
- {
- return $this->_client;
- }
- /**
- * Return array of indices.
- *
- * @return array List of index names
- */
- public function getIndices()
- {
- return $this->_indices;
- }
- /**
- * @return bool
- */
- public function hasIndices()
- {
- return count($this->_indices) > 0;
- }
- /**
- * @param Index|string $index
- *
- * @return bool
- */
- public function hasIndex($index)
- {
- if ($index instanceof Index) {
- $index = $index->getName();
- }
- return in_array($index, $this->_indices);
- }
- /**
- * Return array of types.
- *
- * @return array List of types
- */
- public function getTypes()
- {
- return $this->_types;
- }
- /**
- * @return bool
- */
- public function hasTypes()
- {
- return count($this->_types) > 0;
- }
- /**
- * @param \Elastica\Type|string $type
- *
- * @return bool
- */
- public function hasType($type)
- {
- if ($type instanceof Type) {
- $type = $type->getName();
- }
- return in_array($type, $this->_types);
- }
- /**
- * @return \Elastica\Query
- */
- public function getQuery()
- {
- if (null === $this->_query) {
- $this->_query = Query::create('');
- }
- return $this->_query;
- }
- /**
- * Creates new search object.
- *
- * @param \Elastica\SearchableInterface $searchObject
- *
- * @return Search
- */
- public static function create(SearchableInterface $searchObject)
- {
- return $searchObject->createSearch();
- }
- /**
- * Combines indices and types to the search request path.
- *
- * @return string Search path
- */
- public function getPath()
- {
- if (isset($this->_options[self::OPTION_SCROLL_ID])) {
- return '_search/scroll';
- }
- $indices = $this->getIndices();
- $path = '';
- $types = $this->getTypes();
- if (empty($indices)) {
- if (!empty($types)) {
- $path .= '_all';
- }
- } else {
- $path .= implode(',', $indices);
- }
- if (!empty($types)) {
- $path .= '/'.implode(',', $types);
- }
- // Add full path based on indices and types -> could be all
- return $path.'/_search';
- }
- /**
- * Search in the set indices, types.
- *
- * @param mixed $query
- * @param int|array $options OPTIONAL Limit or associative array of options (option=>value)
- *
- * @throws \Elastica\Exception\InvalidException
- *
- * @return \Elastica\ResultSet
- */
- public function search($query = '', $options = null)
- {
- $this->setOptionsAndQuery($options, $query);
- $query = $this->getQuery();
- $path = $this->getPath();
- $params = $this->getOptions();
- // Send scroll_id via raw HTTP body to handle cases of very large (> 4kb) ids.
- if ('_search/scroll' == $path) {
- $data = [self::OPTION_SCROLL_ID => $params[self::OPTION_SCROLL_ID]];
- unset($params[self::OPTION_SCROLL_ID]);
- } else {
- $data = $query->toArray();
- }
- $response = $this->getClient()->request(
- $path,
- Request::GET,
- $data,
- $params
- );
- return $this->_builder->buildResultSet($response, $query);
- }
- /**
- * @param mixed $query
- * @param $fullResult (default = false) By default only the total hit count is returned. If set to true, the full ResultSet including aggregations is returned
- *
- * @return int|ResultSet
- */
- public function count($query = '', $fullResult = false)
- {
- $this->setOptionsAndQuery(null, $query);
- // Clone the object as we do not want to modify the original query.
- $query = clone $this->getQuery();
- $query->setSize(0);
- $path = $this->getPath();
- $response = $this->getClient()->request(
- $path,
- Request::GET,
- $query->toArray(),
- [self::OPTION_SEARCH_TYPE => self::OPTION_SEARCH_TYPE_QUERY_THEN_FETCH]
- );
- $resultSet = $this->_builder->buildResultSet($response, $query);
- return $fullResult ? $resultSet : $resultSet->getTotalHits();
- }
- /**
- * @param array|int $options
- * @param string|array|\Elastica\Query $query
- *
- * @return $this
- */
- public function setOptionsAndQuery($options = null, $query = '')
- {
- if ('' != $query) {
- $this->setQuery($query);
- }
- if (is_int($options)) {
- $this->getQuery()->setSize($options);
- } elseif (is_array($options)) {
- if (isset($options['limit'])) {
- $this->getQuery()->setSize($options['limit']);
- unset($options['limit']);
- }
- if (isset($options['explain'])) {
- $this->getQuery()->setExplain($options['explain']);
- unset($options['explain']);
- }
- $this->setOptions($options);
- }
- return $this;
- }
- /**
- * @param Suggest $suggest
- *
- * @return $this
- */
- public function setSuggest(Suggest $suggest)
- {
- return $this->setOptionsAndQuery([self::OPTION_SEARCH_TYPE_SUGGEST => 'suggest'], $suggest);
- }
- /**
- * Returns the Scroll Iterator.
- *
- * @see Elastica\Scroll
- *
- * @param string $expiryTime
- *
- * @return Scroll
- */
- public function scroll($expiryTime = '1m')
- {
- return new Scroll($this, $expiryTime);
- }
- /**
- * @return BuilderInterface
- */
- public function getResultSetBuilder()
- {
- return $this->_builder;
- }
- }
|