Elasticsearch Java客户端常用查询操作详解
初始化测试数据
首先通过Bulk API批量插入人物数据到sanguo索引的dahan类型中,用于后续查询演示:
curl -X POST "http://hadoop01:9200/sanguo/dahan/_bulk" -H "Content-Type: application/json" -d '
{ "index": {} }
{"studentNo":1,"name":"刘备","gender":"男","age":24,"birthday":"1985-02-03","classNo":1,"address":"湖南省长沙市","isLeader":true}
{ "index": {} }
{"studentNo":2,"name":"关羽","gender":"男","age":22,"birthday":"1987-08-23","classNo":2,"address":"四川省成都市","isLeader":false}
{ "index": {} }
{"studentNo":3,"name":"糜夫人","gender":"女","age":19,"birthday":"1990-06-12","classNo":1,"address":"上海市","isLeader":false}
{ "index": {} }
{"studentNo":4,"name":"张飞","gender":"男","age":20,"birthday":"1989-07-30","classNo":3,"address":"北京市","isLeader":false}
{ "index": {} }
{"studentNo":5,"name":"诸葛亮","gender":"男","age":18,"birthday":"1992-04-27","classNo":2,"address":"江苏省南京市","isLeader":true}
{ "index": {} }
{"studentNo":6,"name":"孙尚香","gender":"女","age":16,"birthday":"1994-05-21","classNo":3,"address":"广东省深圳市","isLeader":false}
{ "index": {} }
{"studentNo":7,"name":"马超","gender":"男","age":19,"birthday":"1991-10-20","classNo":1,"address":"黑龙江省哈尔滨市","isLeader":false}
{ "index": {} }
{"studentNo":8,"name":"赵云","gender":"男","age":23,"birthday":"1986-10-26","classNo":2,"address":"浙江省杭州市","isLeader":false}
'
1. 全文匹配查询(Match All)
使用matchAllQuery检索指定索引下的所有文档记录。
@Test
public void fetchAllDocuments() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.matchAllQuery())
.get();
SearchHits hits = response.getHits();
System.out.println("总命中数:" + hits.getTotalHits());
for (SearchHit hit : hits) {
Map<String, Object> source = hit.getSource();
System.out.println("姓名: " + source.get("name"));
System.out.println("学号: " + source.get("studentNo"));
System.out.println("性别: " + source.get("gender"));
System.out.println("年龄: " + source.get("age"));
System.out.println("地址: " + source.get("address"));
System.out.println("班级: " + source.get("classNo"));
System.out.println("-".repeat(40));
}
}
2. 字符串解析查询(Query String)
基于Lucene语法对输入文本进行智能解析并执行多字段搜索。
@Test
public void queryStringSearch() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.queryStringQuery("孙尚香"))
.get();
handleSearchResults(response);
}
3. 通配符查询(Wildcard Query)
支持*匹配任意数量字符,?匹配单个字符。注意避免前导星号以防止性能问题。
@Test
public void wildcardAddressSearch() {
// 查找地址以"广东"开头的记录
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.wildcardQuery("address", "广东*"))
.get();
handleSearchResults(response);
}
4. 精确词条查询(Term Query)
对未分词字段进行精确匹配,适用于关键字、枚举值等场景。
@Test
public void termMatchByName() {
// 匹配多个名称中的任意一个
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.termsQuery("name", "刘备", "关羽", "张飞"))
.get();
handleSearchResults(response);
}
5. 字段全文检索(Match Query)
会对查询关键词自动分词,并根据字段映射使用的分析器处理后再匹配。
@Test
public void fullTextSearchByAddress() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.matchQuery("address", "上海"))
.get();
handleSearchResults(response);
}
6. 多字段联合检索(Multi Match)
在多个字段上同时执行相同的查询条件。
@Test
public void multiFieldSearch() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.multiMatchQuery("北京", "name", "address"))
.get();
handleSearchResults(response);
}
7. ID标识查询(IDs Query)
根据文档ID列表直接获取对应数据。
@Test
public void findByIds() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.idsQuery().addIds("AWNkQSCJzU0_wTuf7egi"))
.get();
handleSearchResults(response);
}
8. 模糊相似度查询(Fuzzy Query)
基于编辑距离算法查找拼写相近的内容。可用于容错搜索。
// 添加测试数据
// PUT /sanguo/dahan/123
{
"name": "曹操",
"gender": "男",
"age": 40,
"birthday": "1975-02-03",
"classNo": 1,
"address": "海淀区坐落于北京市",
"isLeader": true
}
// PUT /sanguo/dahan/234
{
"name": "董卓",
"gender": "男",
"age": 35,
"birthday": "1975-02-03",
"classNo": 1,
"address": "北京it程序员",
"isLeader": true
}
@Test
public void fuzzyTextSearch() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.fuzzyQuery("address", "北京市"))
.get();
for (SearchHit hit : response.getHits()) {
System.out.println("相关性得分: " + hit.getScore());
System.out.println("内容: " + hit.getSourceAsString());
}
}
9. 数值与时间范围查询(Range Query)
筛选字段值落在特定区间的文档,支持数字、日期类型。
@Test
public void ageRangeFilter() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.rangeQuery("age")
.from(18).to(22)
.includeLower(true)
.includeUpper(false))
.get();
handleSearchResults(response);
}
10. 布尔组合查询(Bool Query)
通过must、should、mustNot实现复杂逻辑组合查询。
// 新增示例数据
// PUT /sanguo/dahan/345
{
"name": "貂蝉",
"gender": "女",
"age": 16,
"birthday": "2000-02-03",
"classNo": 1,
"address": "北京市女it程序员",
"isLeader": true
}
@Test
public void complexBooleanQuery() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("address", "程序员"))
.must(QueryBuilders.termQuery("gender", "女")))
.get();
handleSearchResults(response);
}
11. 结果排序(Sort Order)
按照指定字段升序或降序排列返回结果。
@Test
public void sortedResultByAge() {
SearchResponse response = client.prepareSearch("sanguo")
.setTypes("dahan")
.setQuery(QueryBuilders.matchAllQuery())
.addSort("age", SortOrder.ASC)
.get();
for (SearchHit hit : response.getHits()) {
System.out.println("姓名: " + hit.getSource().get("name") +
", 年龄: " + hit.getSource().get("age"));
}
}
辅助方法
private void handleSearchResults(SearchResponse response) {
SearchHits hits = response.getHits();
System.out.println("匹配条目数:" + hits.getTotalHits());
for (SearchHit hit : hits) {
Map<String, Object> source = hit.getSource();
System.out.println("→ 姓名:" + source.get("name") +
", 学号:" + source.get("studentNo") +
", 性别:" + source.get("gender") +
", 年龄:" + source.get("age"));
System.out.println(" 地址:" + source.get("address") +
", 班级:" + source.get("classNo"));
System.out.println(" 生日:" + source.get("birthday"));
System.out.println("-".repeat(45));
}
}