第一阶段 06 · 常用查询类速查与示例(每类一个可运行例子)

阶段:第一阶段 / 核心概念

目标:把官方 Java 客户端里最常用的查询类 逐个用例子写出来,

拿来即用。第 05 篇讲的是「类之间的关系与拼接思路」,本篇是「一类一例」的速查手册。

本篇是独立文档 ,示例不依赖任何具体项目。

约定:所有查询返回值统一用实体类 OrderDoc 接收,不用 Map


0. 统一约定(贯穿全篇)

0.1 返回实体类 OrderDoc

java 复制代码
@Data
public class OrderDoc {
    private String id;
    private String region;
    private String status;
    private String channel;
    private BigDecimal amount;
    private String materialDesc;      // 见下方 @JsonProperty 映射
    private LocalDate invoiceDt;

    // ES 字段名是下划线,Java 是驼峰,用 @JsonProperty 映射
    @JsonProperty("material_desc")
    public String getMaterialDesc() { return materialDesc; }
    @JsonProperty("material_desc")
    public void setMaterialDesc(String v) { this.materialDesc = v; }

    @JsonProperty("invoice_dt")
    public LocalDate getInvoiceDt() { return invoiceDt; }
    @JsonProperty("invoice_dt")
    public void setInvoiceDt(LocalDate v) { this.invoiceDt = v; }
}

0.2 通用执行方法(每个例子都调它)

传入一个 Query,统一用 OrderDoc.class 反序列化结果并返回实体列表:

java 复制代码
@Slf4j
@Component
public class OrderSearcher {

    @Autowired
    private ElasticsearchClient client;

    private static final String INDEX = "orders_idx";

    /** 执行查询,返回实体列表(不返回 Map) */
    public List<OrderDoc> search(Query query, int size) throws IOException {
        SearchResponse<OrderDoc> resp = client.search(s -> s
                .index(INDEX)
                .query(query)
                .size(size), OrderDoc.class);          // ← 统一用实体类

        return resp.hits().hits().stream()
                .map(Hit::source)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}

下面每个例子都只展示怎么构造 Query,然后 searcher.search(query, 50) 即可拿到 List<OrderDoc>


1. TermQuery ------ 单值精确匹配(col = ?

不分词的精确匹配,用于 keyword/数值/布尔等字段。

java 复制代码
// WHERE region = 'AP'
Query query = Query.of(q -> q.term(t -> t
        .field("region")
        .value("AP")));

List<OrderDoc> list = searcher.search(query, 50);

坑:不要对 text 字段用 term(被分词,通常查不到);精确匹配请用 keyword 字段。


2. TermsQuery ------ 多值精确匹配(col IN (...)

java 复制代码
// WHERE status IN ('PAID', 'SHIPPED')
List<FieldValue> values = Stream.of("PAID", "SHIPPED")
        .map(FieldValue::of)
        .collect(Collectors.toList());

Query query = Query.of(q -> q.terms(t -> t
        .field("status")
        .terms(tv -> tv.value(values))));

List<OrderDoc> list = searcher.search(query, 50);

关键:terms 需要 List<FieldValue>,字符串要先用 FieldValue::of 转换。


3. RangeQuery ------ 范围(BETWEEN / >= / <=

数值范围:

java 复制代码
// WHERE amount >= 1000 AND amount <= 5000
Query query = Query.of(q -> q.range(r -> r
        .field("amount")
        .gte(JsonData.of(1000))
        .lte(JsonData.of(5000))));

List<OrderDoc> list = searcher.search(query, 50);

日期范围:

java 复制代码
// WHERE invoice_dt BETWEEN '2026-01-01' AND '2026-03-31'
Query query = Query.of(q -> q.range(r -> r
        .field("invoice_dt")
        .gte(JsonData.of("2026-01-01"))
        .lte(JsonData.of("2026-03-31"))));

关键:范围值要用 JsonData.of(...) 包装;gt/gte/lt/lte 分别对应 > >= < <=


4. MatchQuery ------ 全文匹配(分词,text 字段)

对分词字段做全文搜索,命中带相关性打分。

java 复制代码
// 搜 material_desc 里包含 thinkpad / x1 的(会分词)
Query query = Query.of(q -> q.match(m -> m
        .field("material_desc")
        .query("thinkpad x1")));

List<OrderDoc> list = searcher.search(query, 50);

默认多个词是 OR。要求「都命中」用 operator(AND)

java 复制代码
Query query = Query.of(q -> q.match(m -> m
        .field("material_desc")
        .query("thinkpad x1")
        .operator(Operator.And)));      // 所有词都要命中

5. MatchPhraseQuery ------ 短语匹配(保持词序)

要求词连续且顺序一致,相当于精确短语。

java 复制代码
// 命中包含短语 "carbon x1"(顺序不能反)
Query query = Query.of(q -> q.matchPhrase(m -> m
        .field("material_desc")
        .query("carbon x1")));

List<OrderDoc> list = searcher.search(query, 50);

对比:match "carbon x1" 命中含 carbon 或 x1 的;match_phrase 只命中 "carbon x1" 连在一起的。


6. MultiMatchQuery ------ 多字段全文匹配

一个关键字,同时搜多个字段。

java 复制代码
// 在 material_desc 和 region 两个字段里搜 "thinkpad"
Query query = Query.of(q -> q.multiMatch(m -> m
        .fields("material_desc", "region")
        .query("thinkpad")));

List<OrderDoc> list = searcher.search(query, 50);

7. ExistsQuery ------ 字段是否有值(IS NOT NULL

java 复制代码
// WHERE channel IS NOT NULL
Query query = Query.of(q -> q.exists(e -> e
        .field("channel")));

List<OrderDoc> list = searcher.search(query, 50);

要表达 IS NULL,用 bool.must_not(exists)

java 复制代码
// WHERE channel IS NULL
Query query = Query.of(q -> q.bool(b -> b
        .mustNot(mn -> mn.exists(e -> e.field("channel")))));

8. PrefixQuery ------ 前缀匹配(LIKE 'abc%'

java 复制代码
// WHERE region LIKE 'AP%'
Query query = Query.of(q -> q.prefix(p -> p
        .field("region")
        .value("AP")));

List<OrderDoc> list = searcher.search(query, 50);

用于 keyword 字段;前缀匹配比通配符高效。


9. WildcardQuery ------ 通配符(LIKE '%x%'

* 匹配任意多字符,? 匹配单字符。

java 复制代码
// WHERE region LIKE '%MEA%'(如 EMEA)
Query query = Query.of(q -> q.wildcard(w -> w
        .field("region")
        .value("*MEA*")));

List<OrderDoc> list = searcher.search(query, 50);

坑:以 * 开头的通配符很慢(无法用索引前缀),数据量大时慎用。


10. FuzzyQuery ------ 模糊/容错(拼写近似)

允许一定编辑距离,容忍拼写错误。

java 复制代码
// 搜 "thinkpat" 也能命中 "thinkpad"(编辑距离自动)
Query query = Query.of(q -> q.fuzzy(f -> f
        .field("material_desc")
        .value("thinkpat")
        .fuzziness("AUTO")));

List<OrderDoc> list = searcher.search(query, 50);

11. IdsQuery ------ 按 _id 查(WHERE id IN (...)

java 复制代码
// 按文档 _id 批量取
Query query = Query.of(q -> q.ids(i -> i
        .values("1001", "1002", "1003")));

List<OrderDoc> list = searcher.search(query, 50);

12. MatchAllQuery ------ 匹配全部(无 WHERE

java 复制代码
// SELECT * FROM orders LIMIT 50
Query query = Query.of(q -> q.matchAll(m -> m));

List<OrderDoc> list = searcher.search(query, 50);

13. BoolQuery ------ 组合查询(AND / OR / NOT

把上面各种查询组合起来,是最常用的「复合查询」。

java 复制代码
// WHERE region = 'AP'                       (filter,不打分)
//   AND amount >= 1000                      (filter)
//   AND material_desc MATCH 'thinkpad'      (must,打分)
//   AND status <> 'CANCELLED'               (must_not)
Query query = Query.of(q -> q.bool(b -> b
        .must(m -> m.match(mt -> mt.field("material_desc").query("thinkpad")))
        .filter(f -> f.term(t -> t.field("region").value("AP")))
        .filter(f -> f.range(r -> r.field("amount").gte(JsonData.of(1000))))
        .mustNot(mn -> mn.term(t -> t.field("status").value("CANCELLED")))));

List<OrderDoc> list = searcher.search(query, 50);

bool 的详细用法(must/filter/should/must_not、动态拼接、嵌套)见第 05 篇与第 13 篇。


14. 速查总表

查询类 选择器 作用 SQL 类比 本篇
TermQuery .term 单值精确 col = ? §1
TermsQuery .terms 多值精确 col IN (...) §2
RangeQuery .range 范围 BETWEEN §3
MatchQuery .match 全文分词 全文检索 §4
MatchPhraseQuery .matchPhrase 短语 短语匹配 §5
MultiMatchQuery .multiMatch 多字段全文 多列 OR ILIKE §6
ExistsQuery .exists 有无值 IS NOT NULL §7
PrefixQuery .prefix 前缀 LIKE 'abc%' §8
WildcardQuery .wildcard 通配符 LIKE '%x%' §9
FuzzyQuery .fuzzy 模糊容错 近似匹配 §10
IdsQuery .ids _id id IN (...) §11
MatchAllQuery .matchAll 全部 WHERE §12
BoolQuery .bool 组合 AND/OR/NOT §13

15. 坑与最佳实践

  1. 精确匹配用 keywordterm/terms/prefix/wildcard 都作用在不分词字段上。
  2. 全文搜索用 textmatch/match_phrase/multi_match 作用在分词字段上。
  3. termsList<FieldValue>range 值要 JsonData.of(...)
  4. 通配符以 * 开头很慢 ,能用 prefix 就别用前置通配。
  5. 返回统一用实体类 :本篇全程 OrderDoc.class,字段名不一致处用 @JsonProperty 映射。
  6. 组合查询优先 filter :不需要打分的条件放 filter,更快且可缓存。

下一篇

进入第二阶段查询能力:10-match-全文匹配.md

本篇是速查,后续每篇会对单个查询做深入讲解(分词细节、打分、性能等)。

相关推荐
shmily麻瓜小菜鸡4 分钟前
JS/TS 易踩坑知识点 — 模块化与工程化类
开发语言·javascript·ecmascript
geovindu16 分钟前
CSharp: Observer Pattern
开发语言·后端·观察者模式·设计模式·c#·.netcore·行为模式
萧鼎16 分钟前
Python 高性能Web框架神器 FastAPI:自动生成API文、基于Pydant、异步请求处理全搞定
前端·python·fastapi
2601_9622998822 分钟前
Linux执行Python脚本方法
linux·python·脚本·解释器·shebang
郝学胜-神的一滴1 小时前
C++11 工程级应用 09:告别无谓拷贝,解锁高性能移动语义
开发语言·数据结构·c++·vscode·软件工程·visual studio
旋生万物1 小时前
量子纠错容错率87%?螺旋拓扑码用“相位保护“给量子比特上保险(附Python)
python·ai编程·量子计算·量子纠错·螺旋计算
用户8356290780512 小时前
使用 Python 设置 Excel 页眉和页脚
后端·python
databook2 小时前
异常值检测与处理方法总结
python·数据挖掘·数据分析
千里码aicood2 小时前
面向智能助理的多轮医疗对话生成系统开发
python
MC皮蛋侠客2 小时前
OPC UA 系列(一):标准全景与 Python 最小闭环——让第一条设备数据流动起来
开发语言·python·opcua