Hello 大家好,我是兔子 本文将基于Java API Client 8.x版本,通过20个生产级代码示例,深入讲解Elasticsearch的日常高频操作。所有示例可直接复制到项目中运行,并附有最佳实践建议。
废话不多说,上干货
一、基础CRUD操作
1.1 创建索引(指定Mapping)
// 定义商品Mapping
Map<String, Property> properties = new HashMap<>();
properties.put("id", Property.of(p -> p.keyword(k -> k.ignoreAbove(256))));
properties.put("name", Property.of(p -> p.text(t -> t.fielddata(true))));
properties.put("price", Property.of(p -> p.double_(d -> d.index(true))));
properties.put("createTime", Property.of(p -> p.date(d -> d.format("epoch_millis"))));
CreateIndexRequest request = CreateIndexRequest.of(c -> c
.index("products")
.settings(s -> s
.numberOfShards(3)
.numberOfReplicas(1)
)
.mappings(m -> m
.properties(properties)
)
);
client.indices().create(request);
1.2 单文档写入(指定ID)
Product product = new Product("P1001", "无线蓝牙耳机", 299.00);
IndexRequest<Product> request = IndexRequest.of(i -> i
.index("products")
.id(product.getId())
.document(product)
.opType(OpType.Create) // 强制创建,存在则报错
);
IndexResponse response = client.index(request);
System.out.println("文档版本:" + response.version());
1.3 更新文档部分字段
Map<String, JsonData> updateFields = new HashMap<>();
updateFields.put("price", JsonData.of(259.00));
UpdateRequest<Product, Product> request = UpdateRequest.of(u -> u
.index("products")
.id("P1001")
.doc(updateFields)
.docAsUpsert(false) // 不存在不创建
.retryOnConflict(3) // 冲突重试
);
UpdateResponse<Product> response = client.update(request, Product.class);
1.4 批量删除文档
BulkRequest request = BulkRequest.of(b -> b
.index("products")
.operations(
new BulkOperation.Builder().delete(d -> d.id("P1001")).build(),
new BulkOperation.Builder().delete(d -> d.id("P1002")).build()
)
);
BulkResponse response = client.bulk(request);
if (response.errors()) {
response.items().forEach(item -> {
if (item.error() != null) {
System.err.println("删除失败:" + item.id());
}
});
}
二、高级搜索功能
2.1 多字段高亮查询
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.query(q -> q
.multiMatch(m -> m
.query("智能手表")
.fields("name^3", "description")
)
)
.highlight(h -> h
.preTags("<em>")
.postTags("</em>")
.fields(
"name", f -> f.numberOfFragments(0),
"description", f -> f.fragmentSize(150)
)
)
);
SearchResponse<Product> response = client.search(request, Product.class);
response.hits().hits().forEach(hit -> {
Map<String, List<String>> highlights = hit.highlight();
System.out.println("高亮内容:" + highlights.get("name").get(0));
});
2.2 分页查询优化(search_after)
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.size(100)
.sort(so -> so.field(f -> f.field("price").order(SortOrder.Desc)))
.sort(so -> so.field(f -> f.field("_id").order(SortOrder.Asc)))
.searchAfter(JsonData.of("1599.00"), JsonData.of("P1003")) // 上一页最后结果值
);
SearchResponse<Product> response = client.search(request, Product.class);
2.3 模糊搜索(应对拼写错误)
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.query(q -> q
.fuzzy(f -> f
.field("name")
.value("手表")
.fuzziness("1") // 允许1个字符差异
.prefixLength(2) // 前2个字符必须精确
)
)
);
#### 三、聚合分析实战 ##### 3.1 价格区间分布统计
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.size(0)
.aggregations("price_ranges", a -> a
.range(r -> r
.field("price")
.ranges(
new Range.Builder().to(100.0).build(),
new Range.Builder().from(100.0).to(500.0).build(),
new Range.Builder().from(500.0).build()
)
)
)
);
SearchResponse<Product> response = client.search(request, Product.class);
RangeAggregate ranges = response.aggregations().get("price_ranges").range();
ranges.buckets().array().forEach(bucket -> {
System.out.printf("价格区间 %s 有 %d 件商品%n",
bucket.key(), bucket.docCount());
});
3.2 按品牌分组统计(Top10)
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.aggregations("top_brands", a -> a
.terms(t -> t
.field("brand.keyword")
.size(10)
.shardSize(100) // 提升准确度
.order(List.of(
new TermSortOrder.Builder().key("_count").order(SortOrder.Desc).build()
))
)
)
);
#### 四、性能优化技巧 ##### 4.1 查询结果过滤(提升性能)
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.query(q -> q
.bool(b -> b
.filter(f -> f // 不参与评分
.term(t -> t.field("category").value("电子产品"))
)
.must(m -> m
.match(mt -> mt.field("name").query("智能"))
)
)
)
);
4.2 字段数据预加载
UpdateSettingsRequest request = UpdateSettingsRequest.of(u -> u
.index("products")
.settings(s -> s
.indexing(i -> i
.slowlog(sl -> sl
.level("info")
.source("1000") // 记录超过1秒的索引操作
)
)
.mapping(m -> m
.totalFields(tf -> tf.limit(1000)) // 限制字段数量
)
)
);
五、异常处理与监控
5.1 请求超时控制
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.timeout("5s") // 查询超时时间
);
try {
SearchResponse<Product> response = client.search(request, Product.class);
} catch (ElasticsearchException e) {
if (e.status() == 408) {
System.err.println("查询超时,建议优化查询条件");
}
}
5.2 批量操作错误处理
BulkRequest request = BulkRequest.of(b -> b
.operations(/* 批量操作 */)
);
BulkResponse response = client.bulk(request);
response.items().forEach(item -> {
if (item.error() != null) {
System.err.printf("操作失败:%s,原因:%s%n",
item.operationType(), item.error().reason());
}
});
六、企业级实战场景
6.1 日志搜索系统(包含时间范围过滤)
SearchRequest request = SearchRequest.of(s -> s
.index("app-logs-*")
.query(q -> q
.bool(b -> b
.must(m -> m
.matchPhrase(mp -> mp.field("message").query("ERROR"))
)
.filter(f -> f
.range(r -> r
.field("@timestamp")
.gte(JsonData.of("now-1h/d"))
.lte(JsonData.of("now/d"))
)
)
)
)
);
6.2 电商商品推荐(结合用户画像)
SearchRequest request = SearchRequest.of(s -> s
.index("products")
.query(q -> q
.functionScore(fs -> fs
.query(q2 -> q2.matchAll(m -> m))
.functions(fn -> fn
.filter(f -> f.term(t -> t.field("tags").value(userFavoriteTag)))
.weight(2.0)
)
.functions(fn -> fn
.filter(f -> f.range(r -> r.field("sales").gte(1000)))
.weight(1.5)
)
.scoreMode(FunctionScoreMode.Sum)
.boostMode(FunctionBoostMode.Multiply)
)
)
);
最佳实践总结
1. 索引设计原则:
- 控制分片大小(20-50GB为佳)
- 禁用_all字段(7.x后默认禁用)
- 对不需要分析的字段使用keyword类型
2. 查询性能优化:
- 优先使用filter上下文
- 避免wildcard前导通配符
- 合理使用copy_to合并字段
3. Java客户端使用:
- 复用Transport对象(线程安全)
- 批量操作设置合理并发
- 定期检查集群健康状态
欢迎各位在评论区讨论~
喜欢的话可以给博主点点关注哦 ➕