第一阶段 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

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

相关推荐
神经蛙199616 小时前
🌍 别再硬编码中文了!Python Web 项目国际化(i18n)完全指南
后端·python
颜酱16 小时前
14 | 验证并修正 LLM 生成的 SQL
人工智能·python
颜酱16 小时前
13 | 使用 LangChain 生成 SQL
人工智能·python·langchain
春生野草17 小时前
个人笔记——C语言字符串、树
c语言·开发语言·笔记
风中芦苇啊17 小时前
Java EasyExcel 导入通用工具类:自定义注解映射字段 + 反射机制
java·开发语言
PieroPc17 小时前
Python 写的 Windows凭据添加工具 第二版 解决Win11 23H2, 25H2,26H1,共享文件和打印 一部份问题,不是全部!
开发语言·windows·python
颜酱17 小时前
12 | 组装 SQL 生成上下文
人工智能·python
家有娇妻张兔兔17 小时前
Java 对接 PLC 主流型号最合适的方案:Apache PLC4X 实战指南
java·开发语言·plc·modbus·数据缓存·西门子s7·apache plc4x
The_Ticker18 小时前
大宗商品行情API接入教程
开发语言·python·websocket·程序人生·区块链
用户83562907805118 小时前
如何使用 Python 合并多个 Excel 文件
后端·python