肥仔教程网

SEO 优化与 Web 开发技术学习分享平台

玩转ES搜索:BoolQueryBuilder入门

目录

[Elasticsearch 简介](#elasticsearch-简介)

[BoolQueryBuilder 基础概念](#boolquerybuilder-基础概念)

[BoolQueryBuilder 与 MySQL 对比](#boolquerybuilder-与-mysql-对比)

[实际使用示例](#实际使用示例)

[最佳实践](#最佳实践)

[常见问题](#常见问题)

Elasticsearch 简介

Elasticsearch (ES) 是一个基于 Lucene 的分布式搜索引擎,提供了强大的全文搜索和分析能力。与传统的关系型数据库不同,ES 使用 JSON 文档存储数据,并提供了灵活的查询 DSL (Domain Specific Language)。

BoolQueryBuilder 基础概念

BoolQueryBuilder 是 Elasticsearch 中最重要的查询构建器之一,它允许你组合多个查询条件,类似于 SQL 中的 `AND`、`OR`、`NOT` 逻辑操作。

四种子查询类型

BoolQueryBuilder 包含四种子查询类型:

**must** - 必须匹配(相当于 SQL 的 `AND`)

**should** - 应该匹配(相当于 SQL 的 `OR`)

**must_not** - 必须不匹配(相当于 SQL 的 `NOT`)

**filter** - 过滤条件(不计算评分,性能更好)

基本语法结构

[java]

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加 must 条件
boolQuery.must(QueryBuilders.termQuery("status", "published"));
// 添加 should 条件
boolQuery.should(QueryBuilders.matchQuery("title", "elasticsearch"));
// 添加 must_not 条件
boolQuery.mustNot(QueryBuilders.termQuery("deleted", true));
// 添加 filter 条件
boolQuery.filter(QueryBuilders.rangeQuery("publish_date").gte("2023-01-01"));

BoolQueryBuilder 与 MySQL 对比

1. 基本等值查询

MySQL:

[sql]

SELECT * FROM articles WHERE status = 'published';

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("status", "published"));

2. AND 条件组合

MySQL:

[sql]

SELECT * FROM articles
WHERE status = 'published'
AND category = 'tech'
AND author_id = 123;

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("status", "published"))
.must(QueryBuilders.termQuery("category", "tech"))
.must(QueryBuilders.termQuery("author_id", 123));

3. OR 条件组合

MySQL:

[sql]

SELECT * FROM articles
WHERE category = 'tech'
OR category = 'science'
OR category = 'programming';

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("category", "tech"))
.should(QueryBuilders.termQuery("category", "science"))
.should(QueryBuilders.termQuery("category", "programming"))
.minimumShouldMatch(1); // 至少匹配一个条件

4. NOT 条件

MySQL:

[sql]

SELECT * FROM articles
WHERE status = 'published'
AND NOT deleted = true;

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("status", "published"))
.mustNot(QueryBuilders.termQuery("deleted", true));

5. 范围查询

MySQL:

[sql]

SELECT * FROM articles
WHERE publish_date >= '2023-01-01'
AND publish_date <= '2023-12-31'
AND view_count > 1000;

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.filter(QueryBuilders.rangeQuery("publish_date")
.gte("2023-01-01")
.lte("2023-12-31"))
.filter(QueryBuilders.rangeQuery("view_count").gt(1000));

6. LIKE 模糊查询

MySQL:

[sql]

SELECT * FROM articles
WHERE title LIKE '%elasticsearch%'
AND content LIKE '%search%';

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(
QueryBuilders.wildcardQuery("title", "*elasticsearch*"))

.must(
QueryBuilders.wildcardQuery("content", "*search*"));

// 或者使用更适合的 match 查询进行全文搜索
BoolQueryBuilder query2 = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("title", "elasticsearch"))
.must(QueryBuilders.matchQuery("content", "search"));

7. IN 查询

MySQL:

[sql]

SELECT * FROM articles
WHERE category IN ('tech', 'science', 'programming');

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(QueryBuilders.termsQuery("category", "tech", "science", "programming"));

8. 复杂组合查询

MySQL:

[sql]

SELECT * FROM articles
WHERE (status = 'published' OR status = 'featured')
AND category = 'tech'
AND publish_date >= '2023-01-01'
AND NOT author_id = 999;

Elasticsearch:

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.must(QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("status", "published"))
.should(QueryBuilders.termQuery("status", "featured"))
.minimumShouldMatch(1))
.must(QueryBuilders.termQuery("category", "tech"))
.filter(QueryBuilders.rangeQuery("publish_date").gte("2023-01-01"))
.mustNot(QueryBuilders.termQuery("author_id", 999));

实际使用示例

示例1:文章搜索系统

假设我们有一个文章搜索系统,需要根据多个条件搜索文章:

[java]

import
org.elasticsearch.index.query.BoolQueryBuilder;

import
org.elasticsearch.index.query.QueryBuilders;

public class ArticleSearchService {
public BoolQueryBuilder buildArticleQuery(String keyword, String category,
String status, String startDate,
String endDate, Integer minViews) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 关键词搜索(标题和内容)
if (keyword != null && !keyword.isEmpty()) {
BoolQueryBuilder keywordQuery = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("title", keyword).boost(2.0f)) // 标题权重更高
.should(QueryBuilders.matchQuery("content", keyword))
.minimumShouldMatch(1);
boolQuery.must(keywordQuery);
}
// 分类过滤
if (category != null && !category.isEmpty()) {
boolQuery.filter(QueryBuilders.termQuery("category", category));
}
// 状态过滤
if (status != null && !status.isEmpty()) {
boolQuery.filter(QueryBuilders.termQuery("status", status));
}
// 日期范围过滤
if (startDate != null || endDate != null) {
RangeQueryBuilder dateRange = QueryBuilders.rangeQuery("publish_date");
if (startDate != null) dateRange.gte(startDate);
if (endDate != null) dateRange.lte(endDate);
boolQuery.filter(dateRange);
}
// 最小浏览量过滤
if (minViews != null && minViews > 0) {
boolQuery.filter(QueryBuilders.rangeQuery("view_count").gte(minViews));
}
// 排除已删除的文章
boolQuery.mustNot(QueryBuilders.termQuery("deleted", true));
return boolQuery;
}
}

示例2:电商商品搜索

[java]

public class ProductSearchService {
public BoolQueryBuilder buildProductQuery(String searchText, List<String> categories,
Double minPrice, Double maxPrice,
List<String> brands, Boolean inStock) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 商品名称和描述搜索
if (searchText != null && !searchText.isEmpty()) {
BoolQueryBuilder textQuery = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("name", searchText).boost(3.0f))
.should(QueryBuilders.matchQuery("description", searchText))
.should(QueryBuilders.matchQuery("tags", searchText).boost(1.5f))
.minimumShouldMatch(1);
boolQuery.must(textQuery);
}
// 分类筛选
if (categories != null && !categories.isEmpty()) {
boolQuery.filter(QueryBuilders.termsQuery("category", categories));
}
// 价格范围
if (minPrice != null || maxPrice != null) {
RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
if (minPrice != null) priceRange.gte(minPrice);
if (maxPrice != null) priceRange.lte(maxPrice);
boolQuery.filter(priceRange);
}
// 品牌筛选
if (brands != null && !brands.isEmpty()) {
boolQuery.filter(QueryBuilders.termsQuery("brand", brands));
}
// 库存状态
if (inStock != null && inStock) {
boolQuery.filter(QueryBuilders.rangeQuery("stock").gt(0));
}
// 排除下架商品
boolQuery.mustNot(QueryBuilders.termQuery("status", "offline"));
return boolQuery;
}
}

最佳实践

1. 使用 filter 而不是 must 进行精确匹配

[java]

// 推荐:使用 filter,不计算评分,性能更好
boolQuery.filter(QueryBuilders.termQuery("status", "published"));
// 不推荐:使用 must 会计算评分,影响性能
boolQuery.must(QueryBuilders.termQuery("status", "published"));

2. 合理使用 boost 提升相关性

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("title", keyword).boost(2.0f)) // 标题匹配权重更高
.should(QueryBuilders.matchQuery("content", keyword).boost(1.0f)) // 内容匹配标准权重
.should(QueryBuilders.matchQuery("tags", keyword).boost(1.5f)); // 标签匹配中等权重

3. 使用 minimum_should_match 控制 should 条件

[java]

BoolQueryBuilder query = QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("category", "tech"))
.should(QueryBuilders.termQuery("category", "science"))
.should(QueryBuilders.termQuery("category", "programming"))
.minimumShouldMatch(1); // 至少匹配一个条件

4. 嵌套 bool 查询处理复杂逻辑

[java]

// (A AND B) OR (C AND D)
BoolQueryBuilder mainQuery = QueryBuilders.boolQuery()
.should(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("field1", "A"))
.must(QueryBuilders.termQuery("field2", "B")))
.should(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("field3", "C"))
.must(QueryBuilders.termQuery("field4", "D")))
.minimumShouldMatch(1);

5. 性能优化建议

**优先使用 filter**:对于不需要评分的条件,使用 `filter` 而不是 `must`

**缓存友好**:`filter` 查询会被 ES 自动缓存,提高性能

**减少 should 子句**:过多的 should 子句会影响性能

**合理使用通配符**:避免以通配符开头的查询,如 `*term`

常见问题

Q1: must 和 filter 的区别是什么?

A:

`must`:必须匹配,会计算评分,影响文档的相关性得分

`filter`:必须匹配,不计算评分,性能更好,结果会被缓存

Q2: should 查询什么时候会被执行?

A:

如果 bool 查询中有 `must` 或 `filter` 子句,`should` 子句是可选的

如果 bool 查询中只有 `should` 子句,则至少要匹配一个

可以通过 `minimum_should_match` 参数控制必须匹配的 should 子句数量

Q3: 如何实现 SQL 中的 NOT IN?

A: 使用 `must_not` + `terms` 查询:

[java]

boolQuery.mustNot(QueryBuilders.termsQuery("category", "spam", "deleted", "hidden"));

Q4: 如何处理空值查询?

A: 使用 `exists` 查询:

[java]

// 字段存在
boolQuery.filter(QueryBuilders.existsQuery("field_name"));
// 字段不存在
boolQuery.mustNot(QueryBuilders.existsQuery("field_name"));

Q5: 如何实现大小写不敏感的搜索?

A:

使用 `match` 查询(默认大小写不敏感)

或者在索引时使用小写分析器

或者使用 `wildcard` 查询并转换为小写

[java]

// 推荐方式
boolQuery.must(QueryBuilders.matchQuery("title", keyword));
// 或者
boolQuery.must(
QueryBuilders.wildcardQuery("title.keyword", "*" + keyword.toLowerCase() + "*"));

---

总结

BoolQueryBuilder 是 Elasticsearch 中最强大和灵活的查询构建器,它允许你构建复杂的搜索条件。通过理解 `must`、`should`、`must_not` 和 `filter` 的区别,以及与 MySQL SQL 的对应关系,你可以轻松地将传统的 SQL 查询逻辑转换为 ES 查询。

记住以下关键点:

使用 `filter` 进行精确匹配以获得更好的性能

合理使用 `boost` 提升搜索相关性

通过 `minimum_should_match` 控制 `should` 条件的匹配数量

嵌套 bool 查询可以实现复杂的逻辑组合

随着实践经验的积累,你将能够构建出高效且精确的 Elasticsearch 查询。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言