一、初识Elasticsearch与Java客户端

当我们需要处理海量数据的搜索与分析时,Elasticsearch(简称ES)就像一位超级图书馆管理员。作为基于Lucene构建的分布式搜索引擎,它提供了丰富的查询方式和高效的数据处理能力。在实际Java应用中,我们通过Java High Level REST Client(官方推荐的Java客户端)与ES进行交互,本文所有示例均基于Elasticsearch 7.12.0Java 8实现。

项目配置时请确保引入正确依赖:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.0</version>
</dependency>

二、环境搭建与索引准备

假设我们正在开发一个电商搜索引擎,首先需要创建商品索引:

CreateIndexRequest request = new CreateIndexRequest("products");
request.mapping(
    "{\n" +
    "  \"properties\": {\n" +
    "    \"title\": {\"type\": \"text\",\"analyzer\": \"ik_max_word\"},\n" +
    "    \"price\": {\"type\": \"double\"},\n" +
    "    \"category\": {\"type\": \"keyword\"},\n" +
    "    \"create_time\": {\"type\": \"date\"}\n" +
    "  }\n" +
    "}", 
    XContentType.JSON
);
client.indices().create(request, RequestOptions.DEFAULT);

这里特意为category字段设置keyword类型,为后续的term查询埋下伏笔。

三、match查询:智能搜索的核心利器

3.1 基础匹配查询

寻找标题包含"智能手表"的商品:

SearchRequest searchRequest = new SearchRequest("products");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

// 构建match查询(默认OR逻辑)
sourceBuilder.query(QueryBuilders.matchQuery("title", "智能 手表"));

searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

这个查询会匹配到"智能手表"、"智能手环"等相关产品,ES会对查询内容进行分词处理。

3.2 精确匹配增强版

若需要严格匹配完整短语,可使用match_phrase

sourceBuilder.query(
    QueryBuilders.matchPhraseQuery("title", "防水手表")
        .slop(2) // 允许间隔两个词
);

这能命中"防水运动手表"但不会匹配"手表防水套",slop参数提供了灵活的匹配范围。

四、term查询:精准过滤的狙击手

4.1 精确值查找

筛选分类为"electronics"的商品:

sourceBuilder.query(
    QueryBuilders.termQuery("category.keyword", "electronics")
);

注意必须使用.keyword后缀,因为原始字段是text类型。这与我们在索引定义时的keyword类型呼应。

4.2 多值精确匹配

结合terms实现多条件过滤:

sourceBuilder.query(
    QueryBuilders.termsQuery("status", 1, 3, 5)
);

常用于过滤状态码、类型代码等枚举值,比SQL的IN查询更高效。

五、range查询:范围控制的游标

5.1 数值范围查询

查找价格在3000到5000元的商品:

sourceBuilder.query(
    QueryBuilders.rangeQuery("price")
        .gte(3000)
        .lte(5000)
        .boost(1.5f) // 提升相关性评分
);

boost参数可调整查询结果的优先级,这在组合查询中特别有用。

5.2 时间范围过滤

筛选近7天上架的商品:

LocalDateTime now = LocalDateTime.now();
sourceBuilder.query(
    QueryBuilders.rangeQuery("create_time")
        .gte(now.minusDays(7).format(DateTimeFormatter.ISO_DATE_TIME))
        .lte(now.format(DateTimeFormatter.ISO_DATE_TIME))
);

日期字段需遵循严格的ISO格式,可通过Java 8日期API灵活处理。

六、关联技术深度解析

6.1 倒排索引机制

ES的快速搜索能力源于倒排索引,类似于图书最后的关键词索引页。当执行match查询时,ES会自动将查询内容分词,并在倒排索引中快速定位文档。

6.2 文档映射的重要性

在创建索引时设置的字段类型,直接影响查询效果。例如:

  • text类型:适合全文搜索
  • keyword类型:适合精确匹配
  • date类型:支持智能日期计算

七、典型应用场景剖析

  1. 商品搜索引擎(match查询+boost权重)
  2. 日志分析系统(term过滤+range时间范围)
  3. 用户画像系统(terms多值过滤+range年龄区间)

八、技术方案选型对比

查询类型 响应速度 适用场景 注意事项
match ★★★☆ 语义搜索 注意分词策略
term ★★★★ 精确匹配 字段类型需为keyword
range ★★★★ 范围过滤 数值类型需统一

九、避坑指南与最佳实践

  1. 警惕深分页问题:避免使用from(10000).size(10)式查询
  2. 索引分片控制:建议每个分片大小在10-50GB之间
  3. 查询缓存机制:利用requestCache(true)提升重复查询效率
  4. 数据类型校验:避免用range查询text类型字段
  5. 相关性调优:善用explainAPI分析评分逻辑

十、综合应用范例

组合使用三种查询实现精准搜索:

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
    .must(QueryBuilders.matchQuery("title", "智能手机").operator(Operator.AND)) 
    .filter(QueryBuilders.termQuery("category.keyword", "electronics"))
    .filter(QueryBuilders.rangeQuery("price").gte(2000).lte(5000));

sourceBuilder.query(boolQuery);

这种组合拳能精确找到"价格2000-5000元"的"电子类""智能手机"商品,兼顾精准与智能。