《数据查询API探秘:解析高效、精准的数据检索引擎技术》
1. Bool复合查询
bool 查询是 ES 中使用最为广泛的复合查询,可以组合多个查询条件和过滤器,支持must、should、must_not 等子句,可以实现AND、OR、NOT 等逻辑关系操作。
DSL
# 复合查询
GET /customer/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"sex": {
"value": "女"
}
}
},
{
"range": {
"age": {
"lte": 50
}
}
}
],
"should": [
{
"match": {
"address": "云南"
}
}
],
"must_not": [
{
"term": {
"name": {
"value": "谢恨割"
}
}
}
]
}
},
"sort": [
{
"age": {
"order": "asc"
}
}
]
}
java
public void boolQuery() throws IOException {
// 创建搜索request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装bool
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0);
builder.size(20);
BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
queryBuilder.should(QueryBuilders.matchQuery("address", "云南"));
queryBuilder.mustNot(QueryBuilders.termQuery("name", "谢恨割"));
queryBuilder.must(QueryBuilders.termQuery("sex", "女"));
queryBuilder.must(QueryBuilders.rangeQuery("age").lte(50));
// 封装到query中
builder.query(queryBuilder);
// 封装到request中
request.source(builder);
// 请求
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
TotalHits totalHits = res.getHits().getTotalHits();
String s = totalHits.toString();
logger.info("查询DSL:{}", request.source().toString());
logger.info("查询的数据一共有:{}条", res.getHits().getHits().length);
logger.info("查询结果:{}", s);
}
在 Elasticsearch 中,must、should、must_not 是 bool 查询的三个子句,它们分别表示查询必须匹配的条件、可选的条件和必须不匹配的条件。当将它们结合使用时,可以构建出更加精确的查询来满足特定的需求。具体地说,当同时使用must、should、must_not 时,可以得到如下效果:
must 表示必须匹配的条件,如果指定多个 must 条件,则它们都必须被满足。如果某个文档没有满足所有的 must 条件,则该文档将不会被返回。
should 表示可选的条件,至少有一个 should 条件被满足即可。如果指定多个 should
条件,则其中一个被匹配的文档将得到更高的得分。可以通过 minimum_should_match 参数来指定至少有多少个 should 条件需要被匹配才能返回结果。
must_not 表示必须不匹配的条件,如果指定多个 must_not 条件,则所有的条件都必须不被满足。如果某个文档匹配了任何一个 must_not 条件,则该文档将不会被返回。
综上所述,当同时使用 must、should、must_not 时,可以实现更加精确的查询需求,可以满足各种不同场景下的搜索要求。
2. 根据查询条件删除
DSL
# 查询总数
GET customer/_count
{
"query": {
"range": {
"age": {
"lte": 24
}
}
}
}
# 批量删除
POST customer/_delete_by_query
{
"query":{
"range":{
"age":{
"lte":23
}
}
}
}
java
public void deleteByQuery() throws IOException {
// 创建deleteQuery对象
DeleteByQueryRequest request = new DeleteByQueryRequest(EsConfig.INDEX_NAME);
// 指定检索的条件
request.setQuery(QueryBuilders.rangeQuery("age").lte(24));
// 执行删除
BulkByScrollResponse res = client.deleteByQuery(request, RequestOptions.DEFAULT);
// 结果
logger.info("结果:{}", res.toString());
}
3. Filter过滤查询
java
public void filterQuery() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder builder = new SearchSourceBuilder();
// 构造filter查询
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.filter(QueryBuilders.termQuery("address", "云南"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").lte(30));
// 封装到query中
builder.query(boolQueryBuilder);
request.source(builder);
// 请求
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询DSL语句:{}", request.source().toString());
logger.info("查询出的数据:{}条", res.getHits().getHits().length);
logger.info("总数:{}", res.getHits().getTotalHits());
}
DSL
# query,根据你的查询条件,去计算文档的匹配度得到一个分数,并且根据分数进行排序,不会做缓存的。
# filter,根据你的查询条件去查询文档,不去计算分数,而且filter会对经常被过滤的数据进行缓存。
# filter查询
GET /customer/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"address": "云南"
}
},
{
"range": {
"age": {
"lte": 30
}
}
}
]
}
}
}
4. Fuzzy模糊查询
java
public void fuzzyQuery() throws IOException {
// 创建request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.fuzzyQuery("address", "遵义市").prefixLength(3));
request.source(builder);
// 执行请求
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询DSL:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果为:{}", hit.getSourceAsMap());
}
}
DSL
# fuzzy 模糊查詢,指定前面3个字段是不能出错的
GET customer/_search
{
"query": {
"fuzzy": {
"address": {
"value": "遵义市",
"prefix_length": 3,
}
}
}
}
5.Hightlight高亮显示查询
java
public void hightlightQuery() throws IOException {
// 创建查询
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装DSL
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.matchQuery("address", "贵州"));
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("address", 100)
.preTags("</font color='red'>")
.postTags("</font>");
// 封装hightlight查询
builder.highlighter(highlightBuilder);
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询DSL:{}", request.source().toString());
// 输出高亮数据
logger.info("输出高亮数据");
for (SearchHit hit : res.getHits().getHits()) {
HighlightField address = hit.getHighlightFields().get("address");
logger.info("输出高亮数据:{}", address.getFragments()[0]);
}
}
DSL
## highlight高亮查询
GET customer/_search
{
"query": {
"match": {
"address": "贵州"
}
},
"highlight": {
"fields": {
"address": {}
},
"pre_tags": "</font color='red'>",
"post_tags": "</font>"
}
}
## highlight高亮查询
GET customer/_search
{
"query": {
"match": {
"address": {
"query": "贵州",
"operator": "OR",
"prefix_length": 0,
"max_expansions": 50,
"fuzzy_transpositions": true,
"lenient": false,
"zero_terms_query": "NONE",
"auto_generate_synonyms_phrase_query": true,
"boost": 1
}
}
},
"highlight": {
"pre_tags": [
"</font color='red'>"
],
"post_tags": [
"</font>"
],
"fields": {
"address": {
"fragment_size": 100
}
}
}
}
6. 通过id查询
/**
* 通过id查询
*/
@Test
public void findById() throws IOException {
// 创建getRequest
GetRequest request = new GetRequest(EsConfig.INDEX_NAME, "19ada928cb6c474d801fb765742d2403");
// 执行请求
GetResponse res = client.get(request, RequestOptions.DEFAULT);
logger.info("输出结果:{}", res.getSourceAsMap());
}
/**
* 根据多个id进行查询
*/
@Test
public void findByIds() throws IOException {
// 创建查询request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询语句
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.idsQuery().addIds("6d3354d9a67546f4bfb813b1b178d665", "517fafb7d2414f9b892d2bcbcc040f51"));
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("输出结果为:{}", hit.getSourceAsMap());
}
}
DSL
# id查询
GET customer/_doc/f1588e9d82e74edbb1a3437988fd8eb4
GET customer/_search
{
"query": {
"ids":{
"values":["6d3354d9a67546f4bfb813b1b178d665","8456298f1fd040dbb511fe7ebabd3679"]
}
},
}
7. match查询
java
/**
* matchAll查询
*/
@Test
public void matchAllQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(0);
sourceBuilder.size(50);
sourceBuilder.query(QueryBuilders.matchAllQuery());
searchRequest.source(sourceBuilder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
logger.info("查询语句:{}", searchRequest.source().toString());
for (SearchHit hit : search.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
/**
* match 查询
*/
@Test
public void matchQuery() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
searchBuilder.from(0);
searchBuilder.size(40);
searchBuilder.query(QueryBuilders.matchQuery("name.keyword", "张三"));
request.source(searchBuilder);
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
/**
* And布尔match查询
*/
@Test
public void booleanAndMatchQuery() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
searchBuilder.from(0);
searchBuilder.size(40);
searchBuilder.query(QueryBuilders.matchQuery("name", "张三 1").operator(Operator.AND));
request.source(searchBuilder);
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
/**
* OR布尔match查询
*/
@Test
public void booleanOrMatchQuery() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
searchBuilder.from(0);
searchBuilder.size(40);
searchBuilder.query(QueryBuilders.matchQuery("name", "张三 1").operator(Operator.OR));
request.source(searchBuilder);
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
/**
* 多字段匹配查询
*/
@Test
public void multiMatchQuery() throws IOException {
// 请求request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询
SearchSourceBuilder builder = new SearchSourceBuilder();
// mulit_match针对多个Field进行检索,指定的字段会进行分词,精确查找则添加.keyworld
// 没有keyword,则现将张男分词为张和男,在去模糊倒排索引中查询对应的文档
// builder.query(QueryBuilders.multiMatchQuery("张男", "name.keyword", "address"));
builder.query(QueryBuilders.multiMatchQuery("张男", "name", "address"));
request.source(builder);
// 请求查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
for (SearchHit hit : res.getHits().getHits()) {
logger.info("输出结果:{}", hit.getSourceAsMap());
}
}
DSL
# match_all 查询
GET customer/_search
{
"query": {
"match_all": {
}
}
}
# match 查询
GET customer/_search
{
"from":0,
"size":10,
"query":{
"match":{
"name":{
"query":"张三"
}
}
}
}
# 布尔match查询
GET customer/_search
{
"from": 0,
"size": 20,
"query":{
"match": {
"name":{
"query": "张三 1",
"operator": "or",
}
},
},
}
# mulit_match针对多个Field进行检索,指定的字段会进行分词,精确查找则添加.keyworld
# 没有keyword,则现将张男分词为张和男,在去模糊倒排索引中查询对应的文档
GET customer/_search
{
"query": {
"multi_match": {
"query": "张男",
"fields": ["name","address"]
}
}
}
# Ik分词
GET _analyze
{
"analyzer": "ik_max_word",
"text": ["贵州省贵阳市云岩区张男"]
}
8. Prefix前缀查询
java
public void prefixQuery() throws IOException {
// 创建request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.prefixQuery("address", "遵义市"));
request.source(builder);
// 执行请求
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("输出结果为:{}", hit.getSourceAsMap());
}
}
DSL
# perfix 指定前缀查询 前缀查询失效
GET customer/_search
{
"query":{
"prefix": {
"address":{
"value":"贵阳市"
}
}
}
}
9. Range范围查询
java
public void rangeQuery() throws IOException {
// 创建查询request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询语句
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.rangeQuery("age").gte(20).lte(40));
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询DSL语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
DSL
#聚合查询-查询年龄段数量
GET /customer/_search
{
"aggs": {
"agg": {
"range": {
"field": "age",
"ranges": [
{
"to": 20
},
{
"from": 20,
"to": 50
},
{
"from": 50
}
]
}
}
}
}
#range 范围查询
#gt >,gte 》,le <,lte 《
GET customer/_search
{
"query": {
"range": {
"age": {
"gt": 20,
"lte": 80
}
}
}
}
10. Scroll滚动查询
java
public void scrollQuery() throws IOException {
// 创建request
SearchRequest request = new SearchRequest("user");
// 指定生存时间
request.scroll(TimeValue.timeValueMinutes(1));
// 封装查询条件
SearchSourceBuilder builder = new SearchSourceBuilder();
// 每次数据查询200条
builder.size(300);
builder.sort("age", SortOrder.ASC);
builder.query(QueryBuilders.matchAllQuery());
request.source(builder);
// 执行查询结果
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
// 获取scrollId
String scrollId = res.getScrollId();
int i = 1;
logger.info("----------------------------当前正在查看第1页的数据---------------------------------------------");
for (SearchHit hit : res.getHits().getHits()) {
logger.info("首页数据:{}", hit.getSourceAsMap());
}
// 模拟分页查询
while (true) {
// 创建searchScrollRequest
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
// 指定生存时间内
scrollRequest.scroll(TimeValue.timeValueMinutes(1));
// 获取执行获取返回结果
SearchResponse scrollRes = client.scroll(scrollRequest, RequestOptions.DEFAULT);
// 判断是否查询到数据
SearchHit[] hits = scrollRes.getHits().getHits();
if (hits != null && hits.length > 0) {
i = i + 1;
logger.info("----------------------------当前正在查看第{}页的数据---------------------------------------------", i);
for (SearchHit hit : hits) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
} else {
// 没有数据退出
logger.info("----------------------------到底了---------------------------------------------");
break;
}
}
// 删除scrollId
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
// 指定scrolld
clearScrollRequest.addScrollId(scrollId);
// 删除
ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
// 输出结果
logger.info("删除输出结果:{}", clearScrollResponse.isSucceeded());
}
DSL
# 超过1w不支持
GET customer/_search
{
"from": 9999,
"size": 2,
"query": {
"match_all": {}
}
}
# 设置生存时间深度查询,返回scroll_id
GET customer/_search?scroll=1s
{
"query": {
"match_all": {}
},
"size": 20,
"sort": [
{
"age": {
"order": "asc"
}
}
]
}
# 根据scrolld_id和生存时间查询上下文
POST _search/scroll
{
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoAgAAAAAAADByFlUtb1prNTJCUjdXR25mLU5FMG03dVEAAAAAAAAwcRZVLW9aazUyQlI3V0duZi1ORTBtN3VR",
"scroll":"1s"
}
# 删除scroll_id,下次查询的时候会失败
DELETE _search/scroll/DnF1ZXJ5VGhlbkZldGNoAgAAAAAAADByFlUtb1prNTJCUjdXR25mLU5FMG03dVEAAAAAAAAwcRZVLW9aazUyQlI3V0duZi1ORTBtN3VR
11. Term查询文档
java
/**
* term查询
*/
@Test
public void termQuery() throws IOException {
// 创建searchRequest对象
SearchRequest searchRequest = new SearchRequest(EsConfig.INDEX_NAME);
// 指定查询条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(100);
searchSourceBuilder.query(QueryBuilders.termQuery("name.keyword", "张三1"));
searchRequest.source(searchSourceBuilder);
SearchResponse res = client.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit hit : res.getHits().getHits()) {
Map<String, Object> result = hit.getSourceAsMap();
logger.info(result.toString());
}
}
/**
* terms 查询
*/
@Test
public void termsQuery() throws IOException {
// 创建查询对象
SearchRequest searchRequest = new SearchRequest(EsConfig.INDEX_NAME);
// 查询条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(20);
searchSourceBuilder.query(QueryBuilders.termsQuery("name.keyword", "张三1", "张三2", "张三"));
searchRequest.source(searchSourceBuilder);
// 执行查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit hit : search.getHits().getHits()) {
Map<String, Object> map = hit.getSourceAsMap();
logger.info("输出结果:{}", map.toString());
}
}
DSL
# term 查询数据
GET customer/_search
{
"from": 0,
"size": 2,
"query": {
"term": {
"name.keyword": {
"value":"张三1"
}
}
},
}
# terms 查询数据
GET customer/_search
{
"from": 0,
"size": 20,
"query": {
"terms": {
"name.keyword":[
"张三",
"张三2"
]
}
}
}
# 查询数据结构
GET customer011/_mapping
12. 通配符查询
java
public void wildCardQuery() throws IOException {
// 创建request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(QueryBuilders.wildcardQuery("address", "遵义市*"));
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
logger.info("查询DSL语句:{}", request.source().toString());
for (SearchHit hit : res.getHits().getHits()) {
logger.info("查询结果:{}", hit.getSourceAsMap());
}
}
DSL
# wildcard 通配符查询
GET customer/_search
{
"query": {
"wildcard": {
"address": {
"value": "遵义市*"
}
}
}
}
13. 查询去重后的数据
public void cardinalityQuery() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装查询DSL
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.aggregation(AggregationBuilders.cardinality("agg").field("age"));
request.source(builder);
// 执行查询
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 获取返回结果
Aggregation agg = response.getAggregations().get("agg");
logger.info("查询结果:{}", ((ParsedCardinality) agg).getValueAsString());
}
平均数
/**
* 聚合统计查询最小最大
*/
public void extendedStats() throws IOException {
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.aggregation(AggregationBuilders.extendedStats("age").field("age"));
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
ExtendedStats age = res.getAggregations().get("age");
double max = age.getMax();
double min = age.getMin();
double sum = age.getSum();
logger.info("最大年龄:{},最小年龄:{},年龄总和:{}", max, min, sum);
}
范围查询
/**
* 范围查询
*/
public void rangeQuery() throws IOException {
// 创建request
SearchRequest request = new SearchRequest(EsConfig.INDEX_NAME);
// 封装DSL
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.aggregation(AggregationBuilders.range("age").field("age")
.addUnboundedTo(20)
.addRange(20, 50)
.addUnboundedFrom(50));
request.source(builder);
// 执行查询
SearchResponse res = client.search(request, RequestOptions.DEFAULT);
// 获取返回的结果
List<? extends Range.Bucket> buckets = ((ParsedRange) res.getAggregations().get("age")).getBuckets();
for (Range.Bucket bucket : buckets) {
String key = bucket.getKeyAsString();
Object from = bucket.getFrom();
Object to = bucket.getTo();
long docCount = bucket.getDocCount();
logger.info("查询key:{},从{},开始,从{}结束,数量:{}", key, from, to, docCount);
}
}