阶段:第二阶段 / 查询能力
ES 查询:
multi_match| PostgreSQL 对照:多列OR ILIKE
1. 概念
multi_match 是 match 的多字段版本:一个关键词,同时在多个字段里搜 。
典型场景:一个搜索框,输入的词要在「描述、料号、客户名」里都找一遍。
2. PostgreSQL 对照
sql
SELECT * FROM salesdata
WHERE description ILIKE '%carbon%'
OR material ILIKE '%carbon%'
OR customer_nm ILIKE '%carbon%';
multi_match 把这一串 OR ILIKE 收成一个查询,还自带相关性打分。
3. ES DSL
基本用法
GET salesdata_idx/_search
{
"query": {
"multi_match": {
"query": "carbon",
"fields": ["description", "material", "customer_nm"]
}
}
}
字段加权(boost,让某字段更重要)
"multi_match": {
"query": "carbon",
"fields": ["description^3", "material", "customer_nm"]
}
description^3 表示 description 命中的权重是其他字段的 3 倍。
type 常用取值
| type | 行为 |
|---|---|
best_fields(默认) |
取匹配最好的单个字段分数 |
most_fields |
累加各字段分数(越多字段命中越高) |
cross_fields |
把多字段当成一个大字段(适合姓名/地址跨字段) |
phrase |
各字段按短语匹配 |
"multi_match": {
"query": "carbon laptop",
"fields": ["description", "material"],
"type": "cross_fields",
"operator": "and"
}
4. Spring Boot 实现
java
@Component
public class Doc17MultiMatchQuery {
@Autowired
private ElasticsearchClient elasticsearchClient;
/** 一个关键词,多字段搜索 */
public List<Map<String, Object>> multiMatch(String indexName, String keyword,
List<String> fields) throws IOException {
SearchResponse<Map> resp = elasticsearchClient.search(s -> s
.index(indexName)
.query(q -> q.multiMatch(mm -> mm
.query(keyword)
.fields(fields))),
Map.class);
return toSourceList(resp);
}
/** 带字段加权与 type */
public List<Map<String, Object>> multiMatchBoosted(String indexName, String keyword)
throws IOException {
SearchResponse<Map> resp = elasticsearchClient.search(s -> s
.index(indexName)
.query(q -> q.multiMatch(mm -> mm
.query(keyword)
.fields("description^3", "material", "customer_nm")
.type(TextQueryType.BestFields))),
Map.class);
return toSourceList(resp);
}
private List<Map<String, Object>> toSourceList(SearchResponse<Map> resp) {
return resp.hits().hits().stream()
.map(Hit::source).filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
import:
co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType。
返回强类型 Java 对象(推荐,替代裸 Map)
把 Map.class 换成 DTO 的 Class(第 11 篇定义的 OrderDoc,用 @JsonProperty 映射下划线字段),
即可直接拿到强类型列表:
java
/** 一个关键词多字段搜索,返回 List<OrderDoc> */
public List<OrderDoc> multiMatchTyped(String indexName, String keyword, List<String> fields)
throws IOException {
SearchResponse<OrderDoc> resp = elasticsearchClient.search(s -> s
.index(indexName)
.query(q -> q.multiMatch(mm -> mm.query(keyword).fields(fields))),
OrderDoc.class); // ← 关键:DTO 的 Class,而非 Map.class
return resp.hits().hits().stream()
.map(Hit::source).filter(Objects::nonNull)
.collect(Collectors.toList());
}
全文打分场景更常用
Map拿_score/高亮;确定返回结构后,对外接口建议用 DTO。
5. 坑与最佳实践
- 字段类型要一致适配 :全文搜索的字段应是
text;对keyword用 multi_match 效果有限。 - 选对
type:找「哪个字段最匹配」用best_fields;姓名/地址这种跨字段用cross_fields。 - 合理加权 :核心字段
^加权提升排序质量,别所有字段都加。 - 搜索框场景常配
operator=and或minimum_should_match,避免结果太宽泛。
下一篇
18-sort-分页.md。