From b5eadfc26aaae1254e1f38f0ea2d2201178e1cab Mon Sep 17 00:00:00 2001 From: Augustin Date: Sat, 25 Aug 2018 17:11:04 +0200 Subject: [PATCH] Implement an advanced method for searching document (#14) * Provide a custom class SearchParameter that handle all parameter supported by ElasticSearch (only for searching purpose) * Revert the parameter source of the method searchDocumentin favor of a new method advancedSearchDocument (on this way, there is no breaking change between to minor version) --- .circleci/config.yml | 6 +- .../Helper/Nodowntime/IndexHelper.php | 50 +- .../Nodowntime/IndexHelperInterface.php | 16 +- .../Nodowntime/Parameter/SearchParameter.php | 756 ++++++++++++++++++ .../Helper/Nodowntime/DocumentActionTest.php | 17 +- .../Parameter/SearchParameterTest.php | 144 ++++ 6 files changed, 969 insertions(+), 20 deletions(-) create mode 100644 src/Nexucis/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameter.php create mode 100644 tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameterTest.php diff --git a/.circleci/config.yml b/.circleci/config.yml index d227799..e4af13e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/php:7.1.8-browsers + - image: circleci/php:7.2.9-apache-stretch-node-browsers - image: docker.elastic.co/elasticsearch/elasticsearch:6.0.0 working_directory: ~/repo steps: @@ -35,7 +35,7 @@ jobs: analyze_phpcs: docker: - - image: circleci/php:7.1.8-browsers + - image: circleci/php:7.2.9-apache-stretch-node-browsers working_directory: ~/repo steps: - checkout @@ -59,7 +59,7 @@ jobs: analyze_phpstan: docker: - - image: circleci/php:7.1.8-browsers + - image: circleci/php:7.2.9-apache-stretch-node-browsers working_directory: ~/repo steps: - checkout diff --git a/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelper.php b/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelper.php index 98f5b61..3eb291a 100644 --- a/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelper.php +++ b/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelper.php @@ -7,6 +7,7 @@ use Elasticsearch\Common\Exceptions\RuntimeException; use Nexucis\Elasticsearch\Helper\Nodowntime\Exceptions\IndexAlreadyExistException; use Nexucis\Elasticsearch\Helper\Nodowntime\Exceptions\IndexNotFoundException; +use Nexucis\Elasticsearch\Helper\Nodowntime\Parameter\SearchParameter; use stdClass; /** @@ -441,34 +442,59 @@ public function getAllDocuments($alias, $from = 0, $size = 10) * @param string $type * @param int $from the offset from the first result you want to fetch (0 by default) * @param int $size allows you to configure the maximum amount of hits to be returned. (10 by default) - * @param array|null $source allows you to select what fields to be returned (all by default) * @return array * @throws IndexNotFoundException */ - public function searchDocuments($alias, $query = null, $type = null, $from = 0, $size = 10, $source = null) + public function searchDocuments($alias, $query = null, $type = null, $from = 0, $size = 10) { - if (!$this->existsAlias($alias)) { - throw new IndexNotFoundException($alias); + $body = null; + + if (is_array($query)) { + $body = array( + 'query' => $query + ); } - $params = array( - 'index' => $alias, - 'size' => $size, - 'from' => $from, + return $this->advancedSearchDocument( + $alias, + $type, + $body, + (new SearchParameter()) + ->from($from) + ->size($size) ); + } - if (is_array($query)) { - $params['body']['query'] = $query; + /** + * @param $alias [REQUIRED] + * @param string $type + * @param array|null $body + * @param SearchParameter $searchParameter + * @return array + * @throws IndexNotFoundException + */ + public function advancedSearchDocument($alias, $type = null, $body = null, $searchParameter = null) + { + if (!$this->existsAlias($alias)) { + throw new IndexNotFoundException($alias); } - if (is_array($source)) { - $params['_source'] = $source; + $params = array(); + + if ($searchParameter !== null) { + $params = $searchParameter->build(); } + $params['index'] = $alias; + if ($type !== null) { $params['type'] = $type; } + if (is_array($body)) { + $params['body'] = $body; + } + return $this->client->search($params); } diff --git a/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelperInterface.php b/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelperInterface.php index f4753a8..927349e 100644 --- a/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelperInterface.php +++ b/src/Nexucis/Elasticsearch/Helper/Nodowntime/IndexHelperInterface.php @@ -7,6 +7,7 @@ use Elasticsearch\Common\Exceptions\RuntimeException; use Nexucis\Elasticsearch\Helper\Nodowntime\Exceptions\IndexAlreadyExistException; use Nexucis\Elasticsearch\Helper\Nodowntime\Exceptions\IndexNotFoundException; +use Nexucis\Elasticsearch\Helper\Nodowntime\Parameter\SearchParameter; /** * Class IndexHelperInterface @@ -148,6 +149,7 @@ public function getDocument($alias, $type, $id, $refresh = false); * @param string $alias [REQUIRED] * @param int $from the offset from the first result you want to fetch (0 by default) * @param int $size allows you to configure the maximum amount of hits to be returned. (10 by default) + * @throws IndexNotFoundException * @return array */ public function getAllDocuments($alias, $from = 0, $size = 10); @@ -158,10 +160,20 @@ public function getAllDocuments($alias, $from = 0, $size = 10); * @param string $type * @param int $from the offset from the first result you want to fetch (0 by default) * @param int $size allows you to configure the maximum amount of hits to be returned. (10 by default) - * @param array|null $source allows you to select what fields to be returned (all by default) + * @throws IndexNotFoundException + * @return array + */ + public function searchDocuments($alias, $query = null, $type = null, $from = 0, $size = 10); + + /** + * @param $alias + * @param string $type + * @param array|null $body + * @param SearchParameter $searchParameter * @return array + * @throws IndexNotFoundException */ - public function searchDocuments($alias, $query = null, $type = null, $from = 0, $size = 10, $source = null); + public function advancedSearchDocument($alias, $type = null, $body = null, $searchParameter = null); /** * @param string $index [REQUIRED] If the alias is associated to an unique index, you can pass an alias rather than an index diff --git a/src/Nexucis/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameter.php b/src/Nexucis/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameter.php new file mode 100644 index 0000000..11457dd --- /dev/null +++ b/src/Nexucis/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameter.php @@ -0,0 +1,756 @@ + + * @license MIT + */ +class SearchParameter +{ + + public static $OPERATOR_OR = 'OR'; + public static $OPERATOR_AND = 'AND'; + public static $SEARCH_TYPE_DFS_QUERY = 'dfs_query_then_fetch'; + public static $SEARCH_TYPE_QUERY = 'query_then_fetch'; + + /** + * @var string + */ + protected $analyzer; + + /** + * @var bool + */ + protected $analyzeWildcard; + + /** + * Use the constant OPERATOR_OR or OPERATOR_AND to fill this attribute + * @var string + */ + protected $defaultOperator; + + /** + * @var string + */ + protected $df; + + /** + * @var bool + */ + protected $explain; + + /** + * @var array + */ + protected $fields; + /** + * @var int + */ + protected $from; + + /** + * @var string + */ + protected $ignoreIndices; + + /** + * @var array + */ + protected $indicesBoost; + + /** + * @var bool + */ + protected $lenient; + + /** + * @var bool + */ + protected $lowercaseExpandedTerms; + + /** + * @var string + */ + protected $preference; + + /** + * @var string + */ + protected $q; + + /** + * @var bool + */ + protected $queryCache; + + /** + * @var bool + */ + protected $requestCache; + + /** + * @var array + */ + protected $routing; + + /** + * The format shall follow the ElasticSearch time units convention: + * https://www.elastic.co/guide/en/elasticsearch/reference/6.x/common-options.html#time-units + * An example is available here: https://www.elastic.co/guide/en/elasticsearch/reference/6.x/search-request-scroll.html + * @var string + */ + protected $scroll; + + /** + * Use the constant SEARCH_TYPE_DFS_QUERY or SEARCH_TYPE_QUERY to fill this attribute + * See https://www.elastic.co/guide/en/elasticsearch/reference/6.x/search-request-search-type.html + * for more details on the different types of search that can be performed. + * @var string + */ + protected $searchType; + + /** + * @var int + */ + protected $size; + + /** + * @var array + */ + protected $sort; + + /** + * @var string + */ + protected $source; + + /** + * True or false to return the _source field or not, or a list of fields to return + * The corresponding parameter in ElasticSearch is _source + * @var boolean|array + */ + protected $includeSource; + + /** + * A list of fields to exclude from the returned _source field + * The corresponding parameter in ElasticSearch is _source_exclude + * @var array + */ + protected $fieldExcluded; + + /** + * A list of fields to exclude from the returned _source field + * The corresponding parameter in ElasticSearch is _source_include + * @var array + */ + protected $fieldsIncluded; + + /** + * @var array + */ + protected $stats; + + /** + * @var string + */ + protected $suggestField; + + /** + * @var string + */ + protected $suggestMode; + + /** + * @var int + */ + protected $suggestSize; + + /** + * @var string + */ + protected $suggestText; + + /** + * The format shall follow the ElasticSearch time units convention: + * https://www.elastic.co/guide/en/elasticsearch/reference/6.x/common-options.html#time-units + * @var string + */ + protected $timeout; + + /** + * @var boolean + */ + protected $version; + + /** + * @var int + */ + protected $terminateAfter; + + + public function __construct() + { + $this->from = 0; + $this->size = 10; + } + + /** + * Convert the object to an appropriate array with the correct field attempt by ElasticSearch + * @return array + */ + public function build() + { + $params = array(); + $this->buildAnalyzer($params); + $this->buildAnalyzeWildcard($params); + $this->buildDefaultOperator($params); + $this->buildDf($params); + $this->buildExplain($params); + $this->buildFields($params); + $this->buildFrom($params); + $this->buildIgnoreIndices($params); + $this->buildIndicesBoost($params); + $this->buildLenient($params); + $this->buildLowercaseExpendedTerms($params); + $this->buildPreference($params); + $this->buildQuery($params); + $this->buildQueryCache($params); + $this->buildRequestCache($params); + $this->buildRouting($params); + $this->buildScroll($params); + $this->buildSearchType($params); + $this->buildSize($params); + $this->buildSort($params); + $this->buildSource($params); + $this->buildIncludeSource($params); + $this->buildFieldExcluded($params); + $this->buildFieldsIncluded($params); + $this->buildState($params); + $this->buildSuggestField($params); + $this->buildSuggestMode($params); + $this->buildSuggestSize($params); + $this->buildSuggestText($params); + $this->buildTimeout($params); + $this->buildTerminateAfter($params); + $this->buildVersion($params); + + return $params; + } + + /** + * @param string $analyzer + * @return SearchParameter + */ + public function analyzer(string $analyzer) + { + $this->analyzer = $analyzer; + return $this; + } + + /** + * @param bool $analyzeWildcard + * @return SearchParameter + */ + public function analyzeWildcard(bool $analyzeWildcard) + { + $this->analyzeWildcard = $analyzeWildcard; + return $this; + } + + /** + * @param string $defaultOperator + * @return SearchParameter + */ + public function defaultOperator(string $defaultOperator) + { + $this->defaultOperator = $defaultOperator; + return $this; + } + + /** + * @param string $df + * @return SearchParameter + */ + public function df(string $df) + { + $this->df = $df; + return $this; + } + + /** + * @param bool $explain + * @return SearchParameter + */ + public function explain(bool $explain) + { + $this->explain = $explain; + return $this; + } + + /** + * @param array $fields + * @return SearchParameter + */ + public function fields(array $fields) + { + $this->fields = $fields; + return $this; + } + + /** + * @param int $from + * @return SearchParameter + */ + public function from(int $from) + { + $this->from = $from; + return $this; + } + + /** + * @param string $ignoreIndices + * @return SearchParameter + */ + public function ignoreIndices(string $ignoreIndices) + { + $this->ignoreIndices = $ignoreIndices; + return $this; + } + + /** + * @param array $indicesBoost + * @return SearchParameter + */ + public function indicesBoost(array $indicesBoost) + { + $this->indicesBoost = $indicesBoost; + return $this; + } + + /** + * @param bool $lenient + * @return SearchParameter + */ + public function lenient(bool $lenient) + { + $this->lenient = $lenient; + return $this; + } + + /** + * @param bool $lowercaseExpandedTerms + * @return SearchParameter + */ + public function lowercaseExpandedTerms(bool $lowercaseExpandedTerms) + { + $this->lowercaseExpandedTerms = $lowercaseExpandedTerms; + return $this; + } + + /** + * @param string $preference + * @return SearchParameter + */ + public function preference(string $preference) + { + $this->preference = $preference; + return $this; + } + + /** + * @param string $q + * @return SearchParameter + */ + public function q(string $q) + { + $this->q = $q; + return $this; + } + + /** + * @param bool $queryCache + * @return SearchParameter + */ + public function queryCache(bool $queryCache) + { + $this->queryCache = $queryCache; + return $this; + } + + /** + * @param bool $requestCache + * @return SearchParameter + */ + public function requestCache(bool $requestCache) + { + $this->requestCache = $requestCache; + return $this; + } + + /** + * @param array $routing + * @return SearchParameter + */ + public function routing(array $routing) + { + $this->routing = $routing; + return $this; + } + + /** + * @param string $scroll + * @return SearchParameter + */ + public function scroll(string $scroll) + { + $this->scroll = $scroll; + return $this; + } + + /** + * @param string $searchType + * @return SearchParameter + */ + public function searchType(string $searchType) + { + $this->searchType = $searchType; + return $this; + } + + public function size(int $size) + { + $this->size = $size; + return $this; + } + + /** + * @param array $sort + * @return SearchParameter + */ + public function sort(array $sort) + { + $this->sort = $sort; + return $this; + } + + /** + * @param string $source + * @return SearchParameter + */ + public function source(string $source) + { + $this->source = $source; + return $this; + } + + /** + * @param array|bool $includeSource + * @return SearchParameter + */ + public function includeSource($includeSource) + { + $this->includeSource = $includeSource; + return $this; + } + + /** + * @param array $fieldIncluded + * @return SearchParameter + */ + public function includeFieldsFromSource(array $fieldIncluded) + { + $this->fieldsIncluded = $fieldIncluded; + return $this; + } + + /** + * @param array $fieldExcluded + * @return SearchParameter + */ + public function excludeFieldsFromSource(array $fieldExcluded) + { + $this->fieldExcluded = $fieldExcluded; + return $this; + } + + /** + * @param array $stats + * @return SearchParameter + */ + public function stats(array $stats) + { + $this->stats = $stats; + return $this; + } + + /** + * @param string $suggestField + * @return SearchParameter + */ + public function suggestField(string $suggestField) + { + $this->suggestField = $suggestField; + return $this; + } + + /** + * @param string $suggestMode + * @return SearchParameter + */ + public function suggestMode(string $suggestMode) + { + $this->suggestMode = $suggestMode; + return $this; + } + + /** + * @param int $suggestSize + * @return SearchParameter + */ + public function suggestSize(int $suggestSize) + { + $this->suggestSize = $suggestSize; + return $this; + } + + /** + * @param string $suggestText + * @return SearchParameter + */ + public function suggestText(string $suggestText) + { + $this->suggestText = $suggestText; + return $this; + } + + /** + * @param string $timeout + * @return SearchParameter + */ + public function timeout(string $timeout) + { + $this->timeout = $timeout; + return $this; + } + + /** + * @param bool $version + * @return SearchParameter + */ + public function version(bool $version) + { + $this->version = $version; + return $this; + } + + /** + * @param int $terminateAfter + * @return SearchParameter + */ + public function terminateAfter(int $terminateAfter) + { + $this->terminateAfter = $terminateAfter; + return $this; + } + + protected function buildAnalyzer(&$params) + { + $this->buildString($params, 'analyzer', $this->analyzer); + } + + protected function buildAnalyzeWildcard(&$params) + { + $this->buildBoolean($params, 'analyze_wildcard', $this->analyzeWildcard); + } + + protected function buildDefaultOperator(&$params) + { + if (($this->defaultOperator === SearchParameter::$OPERATOR_OR) || ($this->defaultOperator === SearchParameter::$OPERATOR_AND)) { + $params['default_operator'] = $this->defaultOperator; + } + } + + protected function buildDf(&$params) + { + $this->buildString($params, 'df', $this->df); + } + + protected function buildExplain(&$params) + { + $this->buildBoolean($params, 'explain', $this->explain); + } + + protected function buildFields(&$params) + { + $this->buildArray($params, 'fields', $this->fields); + } + + protected function buildFrom(&$param) + { + $param['from'] = $this->from; + } + + protected function buildIgnoreIndices(&$params) + { + $this->buildString($params, 'ignore_indices', $this->ignoreIndices); + } + + protected function buildIndicesBoost(&$params) + { + $this->buildArray($params, 'indices_boost', $this->indicesBoost); + } + + protected function buildLenient(&$params) + { + $this->buildBoolean($params, 'lenient', $this->lenient); + } + + protected function buildLowercaseExpendedTerms(&$params) + { + $this->buildBoolean($params, 'lowercase_expanded_terms', $this->lowercaseExpandedTerms); + } + + protected function buildPreference(&$params) + { + $this->buildString($params, 'preference', $this->preference); + } + + protected function buildQuery(&$params) + { + $this->buildString($params, 'q', $this->q); + } + + protected function buildQueryCache(&$params) + { + $this->buildBoolean($params, 'query_cache', $this->queryCache); + } + + protected function buildRequestCache(&$params) + { + $this->buildBoolean($params, 'request_cache', $this->requestCache); + } + + protected function buildRouting(&$params) + { + $this->buildArray($params, 'routing', $this->routing); + } + + protected function buildScroll(&$params) + { + $this->buildString($params, 'scroll', $this->scroll); + } + + protected function buildSearchType(&$params) + { + if (($this->searchType === SearchParameter::$SEARCH_TYPE_DFS_QUERY) || ($this->searchType === SearchParameter::$SEARCH_TYPE_QUERY)) { + $params['search_type'] = $this->searchType; + } + } + + protected function buildSize(&$params) + { + $params['size'] = $this->size; + } + + protected function buildSort(&$params) + { + $this->buildArray($params, 'sort', $this->sort); + } + + protected function buildSource(&$params) + { + $this->buildString($params, 'source', $this->source); + } + + protected function buildIncludeSource(&$params) + { + if (is_bool($this->includeSource)) { + $params['_source'] = $this->includeSource; + } elseif (is_array($this->includeSource) && (count($this->includeSource) !== 0)) { + $params['_source'] = implode(',', $this->includeSource); + } + } + + protected function buildFieldExcluded(&$params) + { + $this->buildArray($params, '_source_exclude', $this->fieldExcluded); + } + + protected function buildFieldsIncluded(&$params) + { + $this->buildArray($params, '_source_include', $this->fieldsIncluded); + } + + protected function buildState(&$params) + { + $this->buildArray($params, 'stats', $this->stats); + } + + protected function buildSuggestField(&$params) + { + $this->buildString($params, 'suggest_field', $this->suggestField); + } + + protected function buildSuggestMode(&$params) + { + $this->buildString($params, 'suggest_mode', $this->suggestMode); + } + + protected function buildSuggestSize(&$params) + { + $this->buildInt($params, 'suggest_size', $this->suggestSize); + } + + protected function buildSuggestText(&$params) + { + $this->buildString($params, 'suggest_text', $this->suggestText); + } + + protected function buildTimeout(&$params) + { + $this->buildString($params, 'timeout', $this->timeout); + } + + protected function buildTerminateAfter(&$params) + { + $this->buildInt($params, 'terminate_after', $this->terminateAfter); + } + + protected function buildVersion(&$params) + { + $this->buildBoolean($params, 'version', $this->version); + } + + private function buildBoolean(&$params, string $esParam, $attribute) + { + if (is_bool($attribute)) { + $params[$esParam] = $attribute; + } + } + + private function buildInt(&$params, string $esParam, $attribute) + { + if (is_int($attribute) && ($attribute > 0)) { + $params[$esParam] = $attribute; + } + } + + private function buildString(&$params, string $esParam, $attribute) + { + if (is_string($attribute) && strlen($attribute) > 0) { + $params[$esParam] = $attribute; + } + } + + private function buildArray(&$params, string $esParam, $attribute) + { + if (is_array($attribute) && (count($attribute) !== 0)) { + $params[$esParam] = implode(',', $attribute); + } + } +} diff --git a/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/DocumentActionTest.php b/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/DocumentActionTest.php index 07b63b5..1532ead 100644 --- a/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/DocumentActionTest.php +++ b/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/DocumentActionTest.php @@ -2,6 +2,7 @@ namespace Nexucis\Tests\Elasticsearch\Helper\Nodowntime; +use Nexucis\Elasticsearch\Helper\Nodowntime\Parameter\SearchParameter; use stdClass; class DocumentActionTest extends AbstractIndexHelperTest @@ -272,11 +273,21 @@ public function testSearchDocumentsWithSource(string $alias) // create index with some contents $this->loadFinancialIndex($alias, $type); - $query = array( - 'match_all' => new stdClass() + $body = array( + 'query' => array( + 'match_all' => new stdClass() + ) ); - $result = $this->helper->searchDocuments($alias, $query, $type, 0, 10, $expectedFields); + $result = $this->helper->advancedSearchDocument( + $alias, + $type, + $body, + (new SearchParameter()) + ->from(0) + ->size(10) + ->includeSource($expectedFields) + ); $this->assertTrue($result['hits']['total'] > 10); $this->assertTrue(count($result['hits']['hits']) === 10); diff --git a/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameterTest.php b/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameterTest.php new file mode 100644 index 0000000..f13704f --- /dev/null +++ b/tests/Nexucis/Tests/Elasticsearch/Helper/Nodowntime/Parameter/SearchParameterTest.php @@ -0,0 +1,144 @@ +analyzer('my_analyzer') + ->analyzeWildcard(true) + ->defaultOperator(SearchParameter::$OPERATOR_OR) + ->df('prefix') + ->explain(true) + ->fields(array( + 'field1', + 'field2' + )) + ->from(5) + ->ignoreIndices('missing') + ->indicesBoost(array( + 'index1' + )) + ->lenient(false) + ->lowercaseExpandedTerms(false) + ->preference('random') + ->q('lucene query') + ->queryCache(false) + ->requestCache(false) + ->routing(array( + 'routing1', 'routing2' + )) + ->scroll('1m') + ->searchType(SearchParameter::$SEARCH_TYPE_DFS_QUERY) + ->size(87) + ->sort(array( + 'field1:direction1' + )) + ->source('query dsl') + ->includeSource(array( + 'name', + 'id' + )) + ->excludeFieldsFromSource(array( + 'exclude1' + )) + ->includeFieldsFromSource(array( + 'include1', 'include2', 'include3' + )) + ->stats(array( + 'tag1', 'tag2', 'tag3', 'tag4' + )) + ->suggestField('field1') + ->suggestMode('missing') + ->suggestSize(14) + ->suggestText('my suggestion text') + ->timeout('10s') + ->terminateAfter(25) + ->version(true); + + $expectedParams = array( + 'analyzer' => 'my_analyzer', + 'analyze_wildcard' => true, + 'default_operator' => 'OR', + 'df' => 'prefix', + 'explain' => true, + 'fields' => 'field1,field2', + 'from' => 5, + 'ignore_indices' => 'missing', + 'indices_boost' => 'index1', + 'lenient' => false, + 'lowercase_expanded_terms' => false, + 'preference' => 'random', + 'q' => 'lucene query', + 'query_cache' => false, + 'request_cache' => false, + 'routing' => 'routing1,routing2', + 'scroll' => '1m', + 'search_type' => 'dfs_query_then_fetch', + 'size' => 87, + 'sort' => 'field1:direction1', + 'source' => 'query dsl', + '_source' => 'name,id', + '_source_exclude' => 'exclude1', + '_source_include' => 'include1,include2,include3', + 'stats' => 'tag1,tag2,tag3,tag4', + 'suggest_field' => 'field1', + 'suggest_mode' => 'missing', + 'suggest_size' => 14, + 'suggest_text' => 'my suggestion text', + 'timeout' => '10s', + 'terminate_after' => 25, + 'version' => true, + ); + + $params = $search->build(); + $this->assertTrue($this->arraysAreSimilar($expectedParams, $params)); + } + + public function testBuildWithIncludeSourceAsBool() + { + $search = (new SearchParameter()) + ->includeSource(false); + + $expectedParams = array( + 'from' => 0, + 'size' => 10, + '_source' => false + ); + $params = $search->build(); + $this->assertTrue($this->arraysAreSimilar($expectedParams, $params)); + } + + /** + * Snippet found on stack overflow : https://stackoverflow.com/questions/3293531/how-to-permanently-remove-few-commits-from-remote-branch + * Determine if two associative arrays are similar + * + * Both arrays must have the same indexes with identical values + * without respect to key ordering + * + * @param array $a + * @param array $b + * @return bool + */ + private function arraysAreSimilar($a, $b) + { + // if the indexes don't match, return immediately + if (count(array_diff_assoc($a, $b))) { + return false; + } + // we know that the indexes, but maybe not values, match. + // compare the values between the two arrays + foreach ($a as $k => $v) { + if ($v !== $b[$k]) { + return false; + } + } + // we have identical indexes, and no unequal values + return true; + } +}