Shopware6对接Elasticsearch:精准搜索逻辑调整需求
针对你遇到的搜索ABC123返回无关关联结果的问题,核心是要让Elasticsearch只匹配包含该精确连续字符串的文档,而非拆分后的词项或模糊匹配结果。以下是具体落地步骤:
1. 先排查分词逻辑
首先确认Elasticsearch对搜索词的分词结果,避免因分词拆分导致的关联匹配。用Elasticsearch的_analyze API测试:
GET /_analyze { "analyzer": "standard", "text": "ABC123" }
如果返回的token是["abc123"],说明分词器未拆分该字符串,问题出在Shopware的查询逻辑;如果拆分成了["abc", "123"],则需要调整字段的分析器配置。
2. 替换Shopware默认搜索查询
Shopware默认的搜索会使用match查询(支持模糊匹配和多词OR逻辑),你需要通过自定义插件监听搜索事件,替换为精确匹配的查询逻辑:
方法1:使用短语匹配(Match Phrase)
短语匹配会严格匹配连续的字符串序列,适合你的需求。编写事件监听器:
use Shopware\Core\Content\Product\Search\ProductSearchCriteriaEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class ExactProductSearchSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ProductSearchCriteriaEvent::class => 'adjustProductSearch', ]; } public function adjustProductSearch(ProductSearchCriteriaEvent $event): void { $searchTerm = $event->getSearchTerm(); if (empty($searchTerm)) return; // 移除Shopware默认的搜索过滤器 $criteria = $event->getCriteria(); $criteria->removeFilter('search'); // 添加短语匹配过滤器,覆盖名称、SKU等核心字段 $criteria->addFilter(new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter( \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter::CONNECTION_OR, [ new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MatchFilter( 'product.name', $searchTerm, ['operator' => 'phrase'] ), new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MatchFilter( 'product.sku', $searchTerm, ['operator' => 'phrase'] ), // 按需添加其他需要匹配的字段,如description、customFields等 ] )); } }
方法2:使用Keyword字段的Wildcard查询
如果需要更严格的精确子串匹配(区分大小写等),可以用字段的keyword子字段做Wildcard查询(注意:开头带*的Wildcard会影响性能,适合数据量不大的场景):
// 替换上述MultiFilter内的规则为: new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\WildcardFilter( 'product.name.keyword', "*{$searchTerm}*" ), new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\WildcardFilter( 'product.sku.keyword', "*{$searchTerm}*" )
3. 关闭模糊搜索
Shopware默认可能开启了模糊匹配(允许一定字符误差),导致返回类似ABC12、ABC124的结果。可以在MatchFilter中强制关闭:
new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MatchFilter( 'product.name', $searchTerm, [ 'operator' => 'phrase', 'fuzziness' => 0 // 完全禁用模糊匹配 ] )
4. 自定义Elasticsearch字段映射(可选)
如果默认字段的分词器仍会拆分你的搜索词,可以自定义字段映射,添加一个不分词的子字段:
在Shopware自定义插件的Resources/config/elasticsearch/product.json中添加:
{ "properties": { "name": { "type": "text", "fields": { "exact": { "type": "text", "analyzer": "keyword" } } } } }
之后重建Elasticsearch索引,即可用product.name.exact字段进行精确匹配查询。
内容的提问来源于stack exchange,提问作者Ole Dahl Mansfeld

