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

下一篇

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

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

相关推荐
专业程序开发源6 分钟前
springboot欧缇蔓月子中心管理系统82697-计算机课程设计、毕业设计
java·spring boot·后端·python·spring·django·课程设计
FPGA小迷弟9 分钟前
用 Claude Code 重构遗留系统:从评估到落地的完整实践指南
c++·python·ai·plotly·django·ai编程·claude
卷无止境18 分钟前
面向arm64桌面客户端开发全景:语言、框架与生态
后端·python
fanruitian30 分钟前
python else用法
开发语言·python
FRing0340 分钟前
JavaScript入门到精通二十六(变量提升、函数剩余参数、展开运算符、ES6箭头函数)
开发语言·前端·javascript·es6·箭头函数
云深麋鹿43 分钟前
C++ | 基于红黑树实现mymap与myset
开发语言·c++
Thinker QAQ1 小时前
并发编程(十一):Shared Memory 与 Message Passing——关系与组合使用
java·python·go·并发编程·shared memory·message passing
用户8356290780511 小时前
如何使用 Python 对 Excel 数据进行分组和分级显示
后端·python
vx_Biye_Design1 小时前
django房屋租赁推荐系统78455-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·课程设计·express
weixin_417396831 小时前
桌面云终端PXE启动失败怎么排查?从DHCP Option到镜像下发
开发语言·前端·php·技术·酒店·综合布线·弱电