diff --git a/src/module-elasticsuite-core/Api/Index/Mapping/FieldInterface.php b/src/module-elasticsuite-core/Api/Index/Mapping/FieldInterface.php index aaa7f4600..76f130cc5 100644 --- a/src/module-elasticsuite-core/Api/Index/Mapping/FieldInterface.php +++ b/src/module-elasticsuite-core/Api/Index/Mapping/FieldInterface.php @@ -79,6 +79,11 @@ public function getType(); */ public function isSearchable(); + /** + * Is the field searchable and contains reference (sku) data. + */ + public function isSearchableReference(); + /** * Is the field filterable in navigation. * diff --git a/src/module-elasticsuite-core/Api/Index/MappingInterface.php b/src/module-elasticsuite-core/Api/Index/MappingInterface.php index 85a694900..8ab15c219 100644 --- a/src/module-elasticsuite-core/Api/Index/MappingInterface.php +++ b/src/module-elasticsuite-core/Api/Index/MappingInterface.php @@ -29,6 +29,7 @@ interface MappingInterface const DEFAULT_SEARCH_FIELD = 'search'; const DEFAULT_SPELLING_FIELD = 'spelling'; const DEFAULT_AUTOCOMPLETE_FIELD = 'autocomplete'; + const DEFAULT_REFERENCE_FIELD = 'reference'; /** * List of the properties of the mapping. diff --git a/src/module-elasticsuite-core/Api/Search/Request/Container/RelevanceConfigurationInterface.php b/src/module-elasticsuite-core/Api/Search/Request/Container/RelevanceConfigurationInterface.php index c4f2cdb9f..00c7df697 100644 --- a/src/module-elasticsuite-core/Api/Search/Request/Container/RelevanceConfigurationInterface.php +++ b/src/module-elasticsuite-core/Api/Search/Request/Container/RelevanceConfigurationInterface.php @@ -86,4 +86,33 @@ public function getSpanSize(); * @return false|int */ public function getMinScore(); + + /** + * Check if the reference collector field should be used instead of the simple 'sku' field + * when building the exact match filter query. + * + * @return bool + */ + public function isUsingReferenceInExactMatchFilter(); + + /** + * Check if all tokens of the term vectors response should be used. + * + * @return bool + */ + public function isUsingAllTokens(); + + /** + * Check if the term vectors request should also include the reference analyzer collector field. + * + * @return bool + */ + public function isUsingReferenceAnalyzer(); + + /** + * If we should use the default analyzer of each field when building the exact match filter query. + * + * @return bool + */ + public function isUsingDefaultAnalyzerInExactMatchFilter(); } diff --git a/src/module-elasticsuite-core/Api/Search/Spellchecker/RequestInterface.php b/src/module-elasticsuite-core/Api/Search/Spellchecker/RequestInterface.php index 5570f3a5b..a94d9e999 100644 --- a/src/module-elasticsuite-core/Api/Search/Spellchecker/RequestInterface.php +++ b/src/module-elasticsuite-core/Api/Search/Spellchecker/RequestInterface.php @@ -43,4 +43,18 @@ public function getQueryText(); * @return float */ public function getCutoffFrequency(); + + /** + * Is the spellcheck request using all tokens returned by the term vectors. + * + * @return boolean + */ + public function isUsingAllTokens(); + + /** + * Should the spellcheck request target the 'reference' collector field. + * + * @return boolean + */ + public function isUsingReference(); } diff --git a/src/module-elasticsuite-core/Index/Mapping.php b/src/module-elasticsuite-core/Index/Mapping.php index 87d319951..4d0618b4f 100644 --- a/src/module-elasticsuite-core/Index/Mapping.php +++ b/src/module-elasticsuite-core/Index/Mapping.php @@ -62,6 +62,11 @@ class Mapping implements MappingInterface FieldInterface::ANALYZER_WHITESPACE, FieldInterface::ANALYZER_SHINGLE, ], + self::DEFAULT_REFERENCE_FIELD => [ + FieldInterface::ANALYZER_REFERENCE, + FieldInterface::ANALYZER_WHITESPACE, + FieldInterface::ANALYZER_SHINGLE, + ], ]; /** @@ -72,6 +77,7 @@ class Mapping implements MappingInterface private $copyFieldMap = [ 'isSearchable' => self::DEFAULT_SEARCH_FIELD, 'isUsedInSpellcheck' => self::DEFAULT_SPELLING_FIELD, + 'isSearchableReference' => self::DEFAULT_REFERENCE_FIELD, ]; /** diff --git a/src/module-elasticsuite-core/Index/Mapping/Field.php b/src/module-elasticsuite-core/Index/Mapping/Field.php index 98d4b376d..9a817f1e1 100644 --- a/src/module-elasticsuite-core/Index/Mapping/Field.php +++ b/src/module-elasticsuite-core/Index/Mapping/Field.php @@ -118,6 +118,14 @@ public function isSearchable(): bool return (bool) $this->config['is_searchable']; } + /** + * {@inheritdoc} + */ + public function isSearchableReference(): bool + { + return ($this->isSearchable() && (FieldInterface::ANALYZER_REFERENCE === $this->config['default_search_analyzer'])); + } + /** * {@inheritdoc} */ diff --git a/src/module-elasticsuite-core/Search/Adapter/Elasticsuite/Spellchecker.php b/src/module-elasticsuite-core/Search/Adapter/Elasticsuite/Spellchecker.php index 2b13068f9..7b2feb119 100644 --- a/src/module-elasticsuite-core/Search/Adapter/Elasticsuite/Spellchecker.php +++ b/src/module-elasticsuite-core/Search/Adapter/Elasticsuite/Spellchecker.php @@ -20,6 +20,7 @@ use Smile\ElasticsuiteCore\Api\Index\MappingInterface; use Smile\ElasticsuiteCore\Api\Index\Mapping\FieldInterface; use Smile\ElasticsuiteCore\Helper\Cache as CacheHelper; +use Smile\ElasticsuiteCore\Search\Request\RelevanceConfig\App\Config\ScopePool; /** * Spellchecker Elasticsearch implementation. @@ -69,7 +70,7 @@ public function getSpellingType(RequestInterface $request) if ($spellingType === false) { $spellingType = $this->loadSpellingType($request); - $this->cacheHelper->saveCache($cacheKey, $spellingType, [$request->getIndex()]); + $this->cacheHelper->saveCache($cacheKey, $spellingType, [$request->getIndex(), ScopePool::CACHE_TAG]); } return $spellingType; @@ -89,7 +90,7 @@ private function loadSpellingType(RequestInterface $request) try { $cutoffFrequencyLimit = $this->getCutoffrequencyLimit($request); $termVectors = $this->getTermVectors($request); - $queryTermStats = $this->parseTermVectors($termVectors, $cutoffFrequencyLimit); + $queryTermStats = $this->parseTermVectors($termVectors, $cutoffFrequencyLimit, $request->isUsingAllTokens()); if ($queryTermStats['total'] == $queryTermStats['stop']) { $spellingType = self::SPELLING_TYPE_PURE_STOPWORDS; @@ -163,6 +164,11 @@ private function getTermVectors(RequestInterface $request) ], ]; + if ($request->isUsingReference()) { + $doc['fields'][] = MappingInterface::DEFAULT_REFERENCE_FIELD . "." . FieldInterface::ANALYZER_REFERENCE; + $doc['doc'][MappingInterface::DEFAULT_REFERENCE_FIELD] = $request->getQueryText(); + } + $docs = []; // Compute the mtermvector query on all shards to ensure exhaustive results. @@ -185,15 +191,18 @@ private function getTermVectors(RequestInterface $request) * - missing : number of terms of the query not found into the index * - standard : number of terms of the query found using the standard analyzer. * - * @param array $termVectors The term vector query response. - * @param int $cutoffFrequencyLimit Cutoff freq (max absolute number of docs to consider term as a stopword). + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + * + * @param array $termVectors The term vector query response. + * @param int $cutoffFrequencyLimit Cutoff freq (max absolute number of docs to consider term as a stopword). + * @param boolean $useAllTokens Whether to use all tokens or not * * @return array */ - private function parseTermVectors($termVectors, $cutoffFrequencyLimit) + private function parseTermVectors($termVectors, $cutoffFrequencyLimit, $useAllTokens = false) { $queryTermStats = ['stop' => 0, 'exact' => 0, 'standard' => 0, 'missing' => 0]; - $statByPosition = $this->extractTermStatsByPosition($termVectors); + $statByPosition = $this->extractTermStatsByPosition($termVectors, $useAllTokens); foreach ($statByPosition as $positionStat) { $type = 'missing'; @@ -203,6 +212,8 @@ private function parseTermVectors($termVectors, $cutoffFrequencyLimit) $type = 'stop'; } elseif (in_array(FieldInterface::ANALYZER_WHITESPACE, $positionStat['analyzers'])) { $type = 'exact'; + } elseif (in_array(FieldInterface::ANALYZER_REFERENCE, $positionStat['analyzers'])) { + $type = 'exact'; } } $queryTermStats[$type]++; @@ -215,18 +226,20 @@ private function parseTermVectors($termVectors, $cutoffFrequencyLimit) /** * Extract term stats by position from a term vectors query response. - * Wil return an array of doc_freq, analayzers and term by position. + * Will return an array of doc_freq, analyzers and term by position. * * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) * - * @param array $termVectors The term vector query response. + * @param array $termVectors The term vector query response. + * @param boolean $useAllTokens Whether to use all tokens returned in the term vector response. * * @return array */ - private function extractTermStatsByPosition($termVectors) + private function extractTermStatsByPosition($termVectors, $useAllTokens = false) { $statByPosition = []; - $analyzers = [FieldInterface::ANALYZER_STANDARD, FieldInterface::ANALYZER_WHITESPACE]; + $analyzers = [FieldInterface::ANALYZER_STANDARD, FieldInterface::ANALYZER_WHITESPACE, FieldInterface::ANALYZER_REFERENCE]; if (is_array($termVectors) && isset($termVectors['docs'])) { foreach ($termVectors['docs'] as $termVector) { @@ -236,6 +249,9 @@ private function extractTermStatsByPosition($termVectors) foreach ($fieldData['terms'] as $term => $termStats) { foreach ($termStats['tokens'] as $token) { $positionKey = $token['position']; + if ($useAllTokens) { + $positionKey = "{$token['position']}_{$token['start_offset']}_{$token['end_offset']}"; + } if (!isset($termStats['doc_freq'])) { $termStats['doc_freq'] = 0; @@ -265,7 +281,7 @@ private function extractTermStatsByPosition($termVectors) } /** - * Extract analayser from a mapping property name. + * Extract analyser from a mapping property name. * * @param string $propertyName Property name (eg. : search.whitespace) * diff --git a/src/module-elasticsuite-core/Search/Request/Builder.php b/src/module-elasticsuite-core/Search/Request/Builder.php index 066e1c36f..42fd1299c 100644 --- a/src/module-elasticsuite-core/Search/Request/Builder.php +++ b/src/module-elasticsuite-core/Search/Request/Builder.php @@ -240,6 +240,8 @@ private function getSpellingType(ContainerConfigurationInterface $containerConfi 'index' => $containerConfig->getIndexName(), 'queryText' => $queryText, 'cutoffFrequency' => $containerConfig->getRelevanceConfig()->getCutOffFrequency(), + 'isUsingAllTokens' => $containerConfig->getRelevanceConfig()->isUsingAllTokens(), + 'isUsingReference' => $containerConfig->getRelevanceConfig()->isUsingReferenceAnalyzer(), ]; $spellcheckRequest = $this->spellcheckRequestFactory->create($spellcheckRequestParams); diff --git a/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig.php b/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig.php index a4de6b30c..99ef93360 100644 --- a/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig.php +++ b/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig.php @@ -70,22 +70,50 @@ class RelevanceConfig implements RelevanceConfigurationInterface */ private $minScore; + /** + * @var boolean + */ + private $useReferenceInExactMatchFilter; + + /** + * @var boolean + */ + private $useDefaultAnalyzerInExactMatchFilter; + + /** + * @var boolean + */ + private $useAllTokens; + + /** + * @var boolean + */ + private $useReferenceAnalyzer; + /** * RelevanceConfiguration constructor. * * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) * - * @param string $minimumShouldMatch Minimum should match clause of the text query. - * @param float $tieBreaker Tie breaker for multimatch queries. - * @param int|null $phraseMatchBoost The Phrase match boost value, or null if not - * enabled - * @param float $cutOffFrequency The cutoff Frequency value - * @param FuzzinessConfigurationInterface|null $fuzziness The fuzziness Configuration, or null - * @param boolean $enablePhoneticSearch The phonetic Configuration, or null - * @param int|null $spanMatchBoost The Span match boost value, or null if not - * enabled - * @param int|null $spanSize The number of terms to match in span queries - * @param int|null $minScore The Min Score value, or null if not enabled + * @param string $minimumShouldMatch Minimum should match clause of the text query. + * @param float $tieBreaker Tie breaker for multimatch queries. + * @param int|null $phraseMatchBoost The Phrase match boost value, or null if not + * enabled + * @param float $cutOffFrequency The cutoff Frequency value + * @param FuzzinessConfigurationInterface|null $fuzziness The fuzziness Configuration, or null + * @param boolean $enablePhoneticSearch The phonetic Configuration, or null + * @param int|null $spanMatchBoost The Span match boost value, or null if not + * enabled + * @param int|null $spanSize The number of terms to match in span queries + * @param int|null $minScore The Min Score value, or null if not enabled + * @param boolean $useReferenceInExactMatchFilter Whether to use the reference collector field + * instead of 'sku' field in the exact match filter + * @param boolean $useDefaultAnalyzerInExactMatchFilter Whether to use 'field' or 'field.default_analyzer' + * in the exact match filter query + * @param boolean $useAllTokens Whether to take into account all term vector tokens + * @param boolean $useReferenceAnalyzer Whether to include the collector field associated + * with the reference analyzer in term vectors request */ public function __construct( $minimumShouldMatch, @@ -96,7 +124,11 @@ public function __construct( $enablePhoneticSearch = false, $spanMatchBoost = null, $spanSize = null, - $minScore = null + $minScore = null, + $useReferenceInExactMatchFilter = false, + $useDefaultAnalyzerInExactMatchFilter = false, + $useAllTokens = false, + $useReferenceAnalyzer = false ) { $this->minimumShouldMatch = $minimumShouldMatch; $this->tieBreaker = $tieBreaker; @@ -107,6 +139,10 @@ public function __construct( $this->spanMatchBoost = $spanMatchBoost; $this->spanSize = $spanSize; $this->minScore = $minScore; + $this->useReferenceInExactMatchFilter = $useReferenceInExactMatchFilter; + $this->useAllTokens = $useAllTokens; + $this->useReferenceAnalyzer = $useReferenceAnalyzer; + $this->useDefaultAnalyzerInExactMatchFilter = $useDefaultAnalyzerInExactMatchFilter; } /** @@ -194,4 +230,36 @@ public function getMinScore() { return (int) $this->minScore; } + + /** + * {@inheritDoc} + */ + public function isUsingReferenceInExactMatchFilter() + { + return (bool) $this->useReferenceInExactMatchFilter; + } + + /** + * {@inheritDoc} + */ + public function isUsingDefaultAnalyzerInExactMatchFilter() + { + return (bool) $this->useDefaultAnalyzerInExactMatchFilter; + } + + /** + * {@inheritDoc} + */ + public function isUsingAllTokens() + { + return (bool) $this->useAllTokens; + } + + /** + * {@inheritDoc} + */ + public function isUsingReferenceAnalyzer() + { + return (bool) $this->useReferenceAnalyzer; + } } diff --git a/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig/Factory.php b/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig/Factory.php index 5f511984a..0ca838b2a 100644 --- a/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig/Factory.php +++ b/src/module-elasticsuite-core/Search/Request/ContainerConfiguration/RelevanceConfig/Factory.php @@ -73,6 +73,26 @@ class Factory */ const MIN_SCORE_CONFIG_XML_PREFIX = 'min_score_configuration'; + /** + * XML node for exact match configuration + */ + const EXACT_MATCH_CONFIG_XML_PREFIX = 'exact_match_configuration'; + + /** + * XML node for using reference in the exact match filter query + */ + const EXACT_MATCH_USE_REFERENCE_IN_FILTER_XML_PATH = 'exact_match_configuration/use_reference_in_filter'; + + /** + * XML node for tokens usage in term vectors configuration. + */ + const TERM_VECTORS_TOKENS_CONFIG_XML_PATH = 'spellchecking/term_vectors/use_all_tokens'; + + /** + * XML node for reference analyzer usage in term vectors configuration. + */ + const TERM_VECTORS_USE_REFERENCE_CONFIG_XML_PATH = 'spellchecking/term_vectors/use_reference_analyzer'; + /** * @var RelevanceConfigurationInterface[] */ @@ -147,6 +167,10 @@ protected function loadConfiguration($scopeCode) 'spanMatchBoost' => $this->getSpanMatchBoostConfiguration($scopeCode), 'spanSize' => $this->getSpanSize($scopeCode), 'minScore' => $this->getMinScoreConfiguration($scopeCode), + 'useReferenceInExactMatchFilter' => $this->isUsingReferenceInExactMatchFilter($scopeCode), + 'useAllTokens' => $this->isUsingAllTokensConfiguration($scopeCode), + 'useReferenceAnalyzer' => $this->isUsingReferenceAnalyzerConfiguration($scopeCode), + 'useDefaultAnalyzerInExactMatchFilter' => $this->isUsingDefaultAnalyzerInExactMatchFilter($scopeCode), ]; return $configurationParams; @@ -354,4 +378,56 @@ private function getMinScoreConfiguration($scopeCode) return $minScore; } + + /** + * Retrieve reference collector field usage configuration for a container. + * + * @param @param string $scopeCode The scope code + * + * @return bool + */ + private function isUsingReferenceInExactMatchFilter($scopeCode) + { + $path = self::BASE_RELEVANCE_CONFIG_XML_PREFIX . "/" . self::EXACT_MATCH_USE_REFERENCE_IN_FILTER_XML_PATH; + + return (bool) $this->getConfigValue($path, $scopeCode); + } + + /** + * Retrieve term vectors extensive tokens usage configuration for a container. + * + * @param string $scopeCode The scope code + * + * @return bool + */ + private function isUsingAllTokensConfiguration($scopeCode) + { + return (bool) $this->getConfigValue(self::TERM_VECTORS_TOKENS_CONFIG_XML_PATH, $scopeCode); + } + + /** + * Retrieve term vectors reference analyzer usage configuration for a container. + * + * @param string $scopeCode The scope code + * + * @return bool + */ + private function isUsingReferenceAnalyzerConfiguration($scopeCode) + { + return (bool) $this->getConfigValue(self::TERM_VECTORS_USE_REFERENCE_CONFIG_XML_PATH, $scopeCode); + } + + /** + * Check if we should use the default analyzer of each field when building the exact match filter query. + * + * @param @param string $scopeCode The scope code + * + * @return bool + */ + private function isUsingDefaultAnalyzerInExactMatchFilter($scopeCode) + { + $path = self::BASE_RELEVANCE_CONFIG_XML_PREFIX . "/" . self::EXACT_MATCH_CONFIG_XML_PREFIX; + + return (bool) $this->getConfigValue($path . "/use_default_analyzer", $scopeCode); + } } diff --git a/src/module-elasticsuite-core/Search/Request/Query/Fulltext/NonStandardSearchableFieldFilter.php b/src/module-elasticsuite-core/Search/Request/Query/Fulltext/NonStandardSearchableFieldFilter.php new file mode 100644 index 000000000..ed1b0df13 --- /dev/null +++ b/src/module-elasticsuite-core/Search/Request/Query/Fulltext/NonStandardSearchableFieldFilter.php @@ -0,0 +1,35 @@ + + * @copyright 2023 Smile + * @license Open Software License ("OSL") v. 3.0 + */ + +namespace Smile\ElasticsuiteCore\Search\Request\Query\Fulltext; + +use Smile\ElasticsuiteCore\Api\Index\Mapping\FieldInterface; + +/** + * Indicates if a field is used in search with a non-default analyzer. + * + * @category Smile + * @package Smile\ElasticsuiteCore + * @author Romain Ruaud + */ +class NonStandardSearchableFieldFilter extends SearchableFieldFilter +{ + /** + * {@inheritDoc} + */ + public function filterField(FieldInterface $field) + { + return parent::filterField($field) && ($field->getDefaultSearchAnalyzer() !== FieldInterface::ANALYZER_STANDARD); + } +} diff --git a/src/module-elasticsuite-core/Search/Request/Query/Fulltext/QueryBuilder.php b/src/module-elasticsuite-core/Search/Request/Query/Fulltext/QueryBuilder.php index a19087f60..53c5cec54 100644 --- a/src/module-elasticsuite-core/Search/Request/Query/Fulltext/QueryBuilder.php +++ b/src/module-elasticsuite-core/Search/Request/Query/Fulltext/QueryBuilder.php @@ -116,9 +116,28 @@ public function create(ContainerConfigurationInterface $containerConfig, $queryT private function getCutoffFrequencyQuery(ContainerConfigurationInterface $containerConfig, $queryText) { $relevanceConfig = $containerConfig->getRelevanceConfig(); + $fields = array_fill_keys([MappingInterface::DEFAULT_SEARCH_FIELD, 'sku'], 1); + + if ($containerConfig->getRelevanceConfig()->isUsingDefaultAnalyzerInExactMatchFilter()) { + $nonStandardSearchableFieldFilter = $this->fieldFilters['nonStandardSearchableFieldFilter']; + + $fields = $fields + $this->getWeightedFields( + $containerConfig, + null, + $nonStandardSearchableFieldFilter, + MappingInterface::DEFAULT_SEARCH_FIELD + ); + } + + if ($containerConfig->getRelevanceConfig()->isUsingReferenceInExactMatchFilter()) { + $fields += array_fill_keys( + [MappingInterface::DEFAULT_SEARCH_FIELD, MappingInterface::DEFAULT_REFERENCE_FIELD . ".reference"], + 1 + ); + } $queryParams = [ - 'fields' => array_fill_keys([MappingInterface::DEFAULT_SEARCH_FIELD, 'sku'], 1), + 'fields' => array_fill_keys(array_keys($fields), 1), 'queryText' => $queryText, 'cutoffFrequency' => $relevanceConfig->getCutOffFrequency(), 'minimumShouldMatch' => $relevanceConfig->getMinimumShouldMatch(), @@ -200,7 +219,7 @@ private function getPureStopwordsQuery(ContainerConfigurationInterface $containe } /** - * Spellcheked query building. + * Spellchecked query building. * * @param ContainerConfigurationInterface $containerConfig Search request container configuration. * @param string $queryText The text query. diff --git a/src/module-elasticsuite-core/Search/Spellchecker/Request.php b/src/module-elasticsuite-core/Search/Spellchecker/Request.php index e78bbaffe..c93785e68 100644 --- a/src/module-elasticsuite-core/Search/Spellchecker/Request.php +++ b/src/module-elasticsuite-core/Search/Spellchecker/Request.php @@ -40,20 +40,36 @@ class Request implements RequestInterface /** * @var float */ - private $cufoffFrequency; + private $cutoffFrequency; + + /** + * @var boolean + */ + private $isUsingAllTokens; + + /** + * @var boolean + */ + private $isUsingReference; /** * Constructor. * - * @param string $index Spellcheck request index name. - * @param string $queryText Spellcheck fulltext query. - * @param float $cutoffFrequency Spellcheck cutoff frequency (used to detect stopwords). + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + * + * @param string $index Spellcheck request index name. + * @param string $queryText Spellcheck fulltext query. + * @param float $cutoffFrequency Spellcheck cutoff frequency (used to detect stopwords). + * @param boolean $isUsingAllTokens Is spellcheck using all tokens returned by term vectors. + * @param boolean $isUsingReference Should the reference analyzer be included in the spellcheck request. */ - public function __construct($index, $queryText, $cutoffFrequency) + public function __construct($index, $queryText, $cutoffFrequency, $isUsingAllTokens, $isUsingReference) { $this->index = $index; $this->queryText = $queryText; - $this->cufoffFrequency = $cutoffFrequency; + $this->cutoffFrequency = $cutoffFrequency; + $this->isUsingAllTokens = $isUsingAllTokens; + $this->isUsingReference = $isUsingReference; } /** @@ -77,6 +93,22 @@ public function getQueryText() */ public function getCutoffFrequency() { - return $this->cufoffFrequency; + return $this->cutoffFrequency; + } + + /** + * {@inheritDoc} + */ + public function isUsingAllTokens() + { + return $this->isUsingAllTokens; + } + + /** + * {@inheritDoc} + */ + public function isUsingReference() + { + return $this->isUsingReference; } } diff --git a/src/module-elasticsuite-core/Test/Unit/Index/MappingTest.php b/src/module-elasticsuite-core/Test/Unit/Index/MappingTest.php index 53a2e8c21..778cb8e32 100644 --- a/src/module-elasticsuite-core/Test/Unit/Index/MappingTest.php +++ b/src/module-elasticsuite-core/Test/Unit/Index/MappingTest.php @@ -112,7 +112,7 @@ public function testBasicFields() $properties = $this->mapping->getProperties(); $this->assertCount(5, $fields); - $this->assertCount(6, $properties); + $this->assertCount(7, $properties); $this->assertEquals('entity_id', $this->mapping->getIdField()->getName()); $this->assertArrayHasKey('entity_id', $fields); @@ -167,7 +167,7 @@ public function testMappingGeneration() { $mapping = $this->mapping->asArray(); $this->assertArrayHasKey('properties', $mapping); - $this->assertCount(6, $mapping['properties']); + $this->assertCount(7, $mapping['properties']); } /** diff --git a/src/module-elasticsuite-core/etc/adminhtml/elasticsuite_relevance.xml b/src/module-elasticsuite-core/etc/adminhtml/elasticsuite_relevance.xml index 8b9dfdc3b..4be3912a2 100644 --- a/src/module-elasticsuite-core/etc/adminhtml/elasticsuite_relevance.xml +++ b/src/module-elasticsuite-core/etc/adminhtml/elasticsuite_relevance.xml @@ -93,7 +93,21 @@ 1 integer validate-no-empty validate-greater-than-zero - min_score are not included in the search results.]]> + min_score are not included in the search results.]]> + + + + + + + + Magento\Config\Model\Config\Source\Yesno + + + + + Magento\Config\Model\Config\Source\Yesno + @@ -145,6 +159,19 @@ + + + + + Magento\Config\Model\Config\Source\Yesno + + + + + Magento\Config\Model\Config\Source\Yesno + + + diff --git a/src/module-elasticsuite-core/etc/di.xml b/src/module-elasticsuite-core/etc/di.xml index 33020e541..c4735e6bb 100644 --- a/src/module-elasticsuite-core/etc/di.xml +++ b/src/module-elasticsuite-core/etc/di.xml @@ -86,6 +86,7 @@ Smile\ElasticsuiteCore\Search\Request\Query\Fulltext\SearchableFieldFilter + Smile\ElasticsuiteCore\Search\Request\Query\Fulltext\NonStandardSearchableFieldFilter Smile\ElasticsuiteCore\Search\Request\Query\Fulltext\FuzzyFieldFilter Smile\ElasticsuiteCore\Search\Request\Query\Fulltext\NonStandardFuzzyFieldFilter Smile\ElasticsuiteCore\Search\Request\Query\Fulltext\SpannableFieldFilter diff --git a/src/module-elasticsuite-core/etc/elasticsuite_relevance.xml b/src/module-elasticsuite-core/etc/elasticsuite_relevance.xml index dd359f601..cf710eaa6 100644 --- a/src/module-elasticsuite-core/etc/elasticsuite_relevance.xml +++ b/src/module-elasticsuite-core/etc/elasticsuite_relevance.xml @@ -38,6 +38,10 @@ 0 0 + + 0 + 0 + @@ -49,6 +53,10 @@ 1 + + 0 + 0 + diff --git a/src/module-elasticsuite-core/i18n/en_US.csv b/src/module-elasticsuite-core/i18n/en_US.csv index aee9335db..4387ae481 100644 --- a/src/module-elasticsuite-core/i18n/en_US.csv +++ b/src/module-elasticsuite-core/i18n/en_US.csv @@ -78,3 +78,17 @@ Autocomplete,Autocomplete "Enable Boost on Span Match","Enable Boost on Span Match" "Span Match Boost Value","Span Match Boost Value" "Number of words to match at the beginning of the string","Number of words to match at the beginning of the string" +"Exact Match Configuration","Exact Match Configuration" +"[Experimental] Use reference analyzer in exact matching filter query","[Experimental] Use reference analyzer in exact matching filter query" +"Experimental: Instead of the 'sku' field, use the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when building the exact/most exact matching filter query. Useful for sku/reference matching.","Experimental: Instead of the 'sku' field, use the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when building the exact/most exact matching filter query. Useful for sku/reference matching." +"Term Vectors Configuration","Term Vectors Configuration" +"[Experimental] Use all tokens from term vectors","[Experimental] Use all tokens from term vectors" +"Experimental: Take into account all tokens from the term vectors response, instead of one token per position. Useful for sku/reference matching.","Experimental: Take into account all tokens from the term vectors response, instead of one token per position. Useful for sku/reference matching." +"[Experimental] Use reference analyzer in term vectors","[Experimental] Use reference analyzer in term vectors" +"Experimental: Include the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when performing the term vectors request. Useful for sku/reference matching.","Experimental: Include the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when performing the term vectors request. Useful for sku/reference matching." +"[Experimental] Use default analyzer in exact matching filter query","[Experimental] Use default analyzer in exact matching filter query" +"Experimental: Use the default analyzer of each field instead of the 'standard' analyzer for exact matching. Eg : for sku, it will try to match on 'sku.reference' field. If a field is using 'standard_edge_ngram' analyzer, it will try to match on 'field.standard_edge_ngram'. Useful for partial matching, or matching on beginning of words.","Experimental: Use the default analyzer of each field instead of the 'standard' analyzer for exact matching. Eg : for sku, it will try to match on 'sku.reference' field. If a field is using 'standard_edge_ngram' analyzer, it will try to match on 'field.standard_edge_ngram'. Useful for partial matching, or matching on beginning of words." +"Minimum Score Configuration","Minimum Score Configuration" +"Use Min Score","Use Min Score" +"Min Score Value","Min Score Value" +"An integer greater than 0. Documents with a score lower than min_score are not included in the search results.","An integer greater than 0. Documents with a score lower than min_score are not included in the search results." diff --git a/src/module-elasticsuite-core/i18n/fr_FR.csv b/src/module-elasticsuite-core/i18n/fr_FR.csv index f9ec5ef28..d46919106 100644 --- a/src/module-elasticsuite-core/i18n/fr_FR.csv +++ b/src/module-elasticsuite-core/i18n/fr_FR.csv @@ -78,3 +78,17 @@ General,Général "Enable Boost on Span Match","Activer le boost sur le début des champs" "Span Match Boost Value","Valeur du boost" "Number of words to match at the beginning of the string","Nombre de mots à matcher au début des champs" +"Exact Match Configuration","Configuration Recherche Exacte" +"[Experimental] Use reference analyzer in exact matching filter query","[Expérimental] Utiliser l'analyseur reference dans le filtre de requête d'exact matching" +"Experimental: Instead of the 'sku' field, use the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when building the exact/most exact matching filter query. Useful for sku/reference matching.","Expérimental: Plutôt que le champ 'sku' seul, utiliser le champ collecteur 'reference' qui contient tous les champs cherchables utilisant l'analyseur 'reference' lors de la construction du filtre de requête exact/most exact. Utile pour le matching de sku/références produit." +"Term Vectors Configuration","Configuration des Term Vectors" +"[Experimental] Use all tokens from term vectors","[Expérimental] Utiliser tous les tokens des term vectors" +"Experimental: Take into account all tokens from the term vectors response, instead of one token per position. Useful for sku/reference matching.","Expérimental: Prendre en considération tous les tokens de la réponse des term vectors, plutôt qu'un seul token par position. Utile pour matcher les sku/références." +"[Experimental] Use reference analyzer in term vectors","[Expérimental] Utiliser l'analyseur reference dans les term vectors" +"Experimental: Include the 'reference' collector field which contains all searchable fields using the 'reference' analyzer when performing the term vectors request. Useful for sku/reference matching.","Expérimental: Inclure le champ collecteur 'reference' qui contient tous les champs cherchables utilisant l'analyseur 'reference' lors de la requête des term vectors. Utile pour le matching de sku/références produit." +"[Experimental] Use default analyzer in exact matching filter query","[Expérimental] Utiliser l'analyseur par défaut des champs dans la recherche exacte" +"Experimental: Use the default analyzer of each field instead of the 'standard' analyzer for exact matching. Eg : for sku, it will try to match on 'sku.reference' field. If a field is using 'standard_edge_ngram' analyzer, it will try to match on 'field.standard_edge_ngram'. Useful for partial matching, or matching on beginning of words.","Expérimental: Utiliser l'analyseur par défaut de chaque champ au lieu de l'analyseur 'standard' pour la recherch exacte. Ex : pour le sku, le moteur essayera de trouver une correspondance exacte sur sku.reference. Si un champ a pour analyseur 'standard_edge_ngram', le moteur tentera de trouver une correspondance exacte sur 'champ.standard_edge_ngram'. Utile pour le matching partiel, ou le matching sur les débuts de mots." +"Minimum Score Configuration","Score minimum" +"Use Min Score","Utiliser un score minimum" +"Min Score Value","Score minimum" +"An integer greater than 0. Documents with a score lower than min_score are not included in the search results.","Un entier supérieur à 0. Les documents ayant un score inférieur à min_score ne seront plus inclus dans les résultats de recherche."