Laravel中Elasticsearch如何实现字符串精确包含匹配查询
实现Elasticsearch类似SQL LIKE '%query%'的精确包含匹配
你当前使用phrase_prefix类型的multi_match查询,逻辑是匹配以查询短语为前缀的连续词序列,和SQL中LIKE '%query%'(任意位置包含子串)的逻辑完全不同,所以无法得到期望结果。可以通过以下两种方式解决:
方案1:快速调整查询逻辑(无需修改索引映射)
使用query_string查询,支持通配符*来模拟LIKE的模糊匹配效果:
public function searchAdverts(string $query) { $params = [ 'index' => 'adverts', 'body' => [ 'query' => [ 'query_string' => [ 'query' => "*{$query}*", 'fields' => ['title', 'content'] ] ] ] ]; $response = $this->client->search($params); return $response; }
注意:这种方式适合临时需求,如果查询词过短(1-2个字符),会因为需要遍历大量分词结果导致性能下降。
方案2:优化索引映射(高效长期方案)
默认的text字段会被分词器拆分,无法高效匹配任意子串。可以给title和content添加keyword类型的子字段,同时保留原字段的全文检索能力:
修改后的索引映射
'index' => 'adverts', 'body' => [ 'mappings' => [ 'properties' => [ 'id' => ['type' => 'integer'], 'title' => [ 'type' => 'text', 'fields' => [ 'keyword' => [ 'type' => 'keyword', 'ignore_above' => 256 // 根据实际内容长度调整 ] ] ], 'content' => [ 'type' => 'text', 'fields' => [ 'keyword' => [ 'type' => 'keyword', 'ignore_above' => 1024 ] ] ], ] ], ]
注意:修改映射后需要重新索引所有数据,新映射才会生效。
对应的查询代码
使用wildcard查询针对keyword子字段,实现和LIKE '%query%'完全一致的逻辑,且性能更优:
public function searchAdverts(string $query) { $params = [ 'index' => 'adverts', 'body' => [ 'query' => [ 'bool' => [ 'should' => [ [ 'wildcard' => [ 'title.keyword' => "*{$query}*" ] ], [ 'wildcard' => [ 'content.keyword' => "*{$query}*" ] ] ] ] ] ] ]; $response = $this->client->search($params); return $response; }
内容的提问来源于stack exchange,提问作者Dmitrijs
相关产品推荐
相关产品推荐

