Elasticsearch-Query DSL

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch-Query DSL相关的知识,希望对你有一定的参考价值。

  • 一、查询DSL
    0、基础查询语法
  • 1、查询所有&全文检索
  • 2、精确查询
  • 3、地理查询
  • 4、复合查询
  • 二、搜索结果处理
    1、排序
  • 2、分页
  • 3、高亮

三、RestClient查询
1、match_all查询
2、全文检索查询
3、精确查询
4、复合查询
5、排序和分页
6、高亮
7、距离排序
8、组合查询

一、查询DSL

Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。

  • 查询所有:查询出所有数据,一般测试用。例如:​​match_all​​;
  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:​​match_query​​、​​multi_match_query​​;
  • 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:​​ids​​、​​range​​、​​term​​;
  • 地理(geo)查询:根据经纬度查询。例如:​​geo_distance​​、​​geo_bounding_box​​;
  • 复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:​​bool​​、​​function_score​​。

0、基础查询语法


GET /indexName/_search

"query":
"查询类型":
"查询条件": "条件值"


1、查询所有&全文检索

  • ① ​​match_all​​查询所有


GET /indexName/_search

"query":
"match_all":

  • ② ​​match​​根据一个字段查询


GET /indexName/_search

"query":
"match":
"FIELD": "TEXT"


  • ③ ​​multi_match​​根据多个字段查询


GET /indexName/_search

"query":
"multi_match" :
"query": "TEXT",
"fields": [ "FIELD1", "*FIELD2" ]


实例:


# match_all查询所有
GET /hotel/_search

"query":
"match_all":


# match根据一个字段查询
GET /hotel/_search

"query":
"match":
"all": "外滩"



# multi_match根据多个字段查询
GET /hotel/_search

"query":
"multi_match":
"query": "外滩如家",
"fields": ["name","brand","business"]


  • ④ ​​match​​和​​multi_match​​的区别

match:根据一个字段查询;

multi_match​:根据多个字段查询,参与查询字段越多,查询性能越差。

2、精确查询

  • ① ​​term​​根据词条精确查询


GET /indexName/_search

"query":
"term":
"FIELD":
"value": "VALUE"



  • ② ​​range​​根据值的范围查询


GET /indexName/_search

"query":
"range":
"FIELD":
"gte": value,
"lte": value



实例:


# term根据词条精确查询
GET /hotel/_search

"query":
"term":
"city":
"value": "上海"




# range根据值的范围查询
GET /hotel/_search

"query":
"range":
"price":
"gte": 300,
"lt": 350



  • ③ 常见的精确查询

term:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段;

range:根据数值范围查询,可以是数值日期​的范围。

3、地理查询

  • ① ​​geo_bounding_box​​矩形范围查询


GET /indexName/_search

"query":
"geo_bounding_box":
"FIELD":
"top_left":
"lat": value,
"lon": value
,
"bottom_right":
"lat": value,
"lon": value




  • ② ​​geo_distance​​圆形范围查询


GET /indexName/_search

"query":
"geo_distance":
"distance": "XXkm",
"FIELD":
"lat": value,
"lon": value



实例:


# geo_bounding_box矩形范围查询
GET /hotel/_search

"query":
"geo_bounding_box":
"location":
"top_left":
"lat": 40.8,
"lon": -74.0
,
"bottom_right":
"lat": 40.7,
"lon": -73.0





# geo_distance圆形范围查询
GET /hotel/_search

"query":
"geo_distance":
"distance": "1km",
"location":
"lat": 40.715,
"lon": -73.988



4、复合查询

  • ① ​​function_score​​算分查询

官方文档:Function score query。


GET /indexName/_search

"query":
"function_score":
"query": "match": "FIELD": "TEXT" , //原始查询条件
"functions": [

"filter": "term": "FIELD": "TEXT" , //过滤条件
"weight": VALUE //算分函数:script_score、weight、random_score、field_value_factor

],
"boost_mode": "MODE" //加权模式:multiply、replace、sum、avg、max、min


​function_score​​​ query定义的三要素:
过滤条件:哪些文档要加分;

算分函数:如何计算function score;

加权方式​:function score 与 query score如何运算。

  • ② ​​bool query​​复合查询

官方文档:Boolean query


GET /indexName/_search

"query":
"bool" :
"must" :
"term" : "FIELD" : "TEXT"
,
"filter":
"term" : "FIELD" : "TEXT"
,
"must_not" :
"range" :
"FIELD" : "gte" : VALUE, "lte" : VALUE

,
"should" : [
"term" : "FIELD" : "TEXT" ,
"term" : "FIELD" : "TEXT"
],
"minimum_should_match" : 1


​bool query​​​四种逻辑关系:
must:必须匹配的条件,可以理解为“与”;

should:选择性匹配的条件,可以理解为“或”;

must_not:必须不匹配的条件,不参与打分;

filter​:必须匹配的条件,不参与打分。


二、搜索结果处理

1、排序

ES支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:​​keyword​​类型、​​数值​​类型、​​地理坐标​​类型、​​日期​​类型等。


GET /indexName/_search

"query" :
"match_all" :
,
"sort" : [
"FIELD" : "MODE" // desc、asc
]


GET /indexName/_search

"query" :
"term" : "user" : "kimchy"
,
"sort" : [

"_geo_distance" :
"FIELD" : [lat, lon],
"order" : "asc",
"unit" : "km"


]

实例:


GET /hotel/_search

"query":
"match_all":
,
"sort": [

"score":
"order": "desc"
,
"price":
"order": "asc"


]


# 121.612534,31.035087
GET /hotel/_search

"query":
"match_all":
,
"sort": [

"_geo_distance":
"location":
"lat": 31.035087,
"lon": 121.612534
,
"order": "asc",
"unit": "km"


]

2、分页

ES默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。ES中通过修改​​from​​、​​size​​参数来控制要返回的分页结果。


GET /indexName/_search

"query" :
"match_all" :
,
"from": PAGE,
"size": PAGESIZE,
"sort" : [
"FIELD" : "MODE" // desc、asc
]
  • from + size
    优点:支持随机翻页
  • 缺点:深度分页问题,默认查询上限(from + size)是10000
    场景:百度、京东、谷歌、淘宝这样的随机翻页搜索
  • after search
    优点:没有查询上限(单次查询的size不超过10000)
  • 缺点:只能向后逐页查询,不支持随机翻页
    场景:没有随机翻页需求的搜索,例如手机向下滚动翻页
  • scroll
    优点:没有查询上限(单次查询的size不超过10000)
  • 缺点:会有额外内存消耗,并且搜索结果是非实时的 场景:海量数据的获取和迁移。从ES7.1开始不推荐,建议用 after search方案。

实例:


GET /hotel/_search

"query":
"match_all":
,
"sort": [

"price":
"order": "asc"


],
"from": 0,
"size": 5

3、高亮

高亮:就是在搜索结果中把搜索关键字突出显示。


GET /indexName/_search

"query" :
"match" :
"FIELD" : "TEXT"

,
"highlight":
"fields" :
"FIELD" : // 指定高亮的字段
"pre_tags": "<em>", //标记高亮字段的前置标签
"post_tags": "</em>" //标记高亮字段的后置标签



实例:


GET /hotel/_search

"query":
"match":
"all": "如家"

,
"highlight":
"fields":
"name":
"require_field_match": "false"




三、RestClient查询

1、match_all查询

步骤: ① 获取request对象;

② 设置DSL语句;

③ 发送请求request,获取响应response

④ 处理响应response​,返回结果。


@Test
void matchAll()
try
// 1. 获取request对象
SearchRequest request = new SearchRequest("hotel");

// 2. 设置查询条件
request.source()
.query(QueryBuilders.matchAllQuery());

// 3. 发送请求,获得响应
SearchResponse response = client.search(request, RequestOptions.DEFAULT);

// 4. 处理查询结果输出
handleResponse(response);
catch (IOException e)
throw new RuntimeException(e);

【Elasticsearch-Query


封装处理响应的方法:


private void handleResponse(SearchResponse response) throws IOException 
// 4. 获取搜索内容
long count = response.getHits().getTotalHits().value;
System.out.println("搜索到的条数为:" + count + "条。");

SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits)
// 4.1 将资源json串转换为对象
HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), HotelDoc.class);
// 4.2 打印输出对象
System.out.println(hotelDoc);

【Elasticsearch-Query


2、全文检索查询

  • ① match单字段查询


// 1. match 单字段查询
QueryBuilders.matchQuery("all", "如家");


GET /hotel/_search

"query":
"match":
"all": "如家"


  • ② multi_match多字段查询


// 2. multiMatch 多字段查询
QueryBuilders.multiMatchQuery("如家", "name", "business");


GET /hotel/_search

"query":
"multi_match":
"query": "如家",
"fields": ["name","brand","business"]


3、精确查询

  • ① term查询


// 3. term 查询
QueryBuilders.termQuery("city", "杭州");


GET /hotel/_search

"query":
"term":
"city":
"value": "杭州"



  • ② range查询


// 4. range 查询
QueryBuilders.rangeQuery("price").gte(100).lte(300);


GET /hotel/_search

"query":
"range":
"price":
"gte": 100,
"lt": 300



4、复合查询


// 2. 设置DSL语句
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 2.1 添加must条件
boolQuery.must(QueryBuilders.termQuery("name", "上海"));
// 2.2 添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte("250"));
// 2.3 设置查询
request.source()
.query(boolQuery);

【Elasticsearch-Query


5、排序和分页


// 2. 设置DSL语句
request.source().query(QueryBuilders.matchQuery("name", "如家"));
// 2.1 排序
request.source().sort("price", SortOrder.ASC);
// 2.2 分页
request.source().from((page - 1) * pageSize).size(pageSize); // 此处from从0开始计数,第0条

【Elasticsearch-Query


6、高亮

  • ① 高亮DSL准备


// 2.2 设置高亮结果
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));

【Elasticsearch-Query


  • ② 解析高亮结果


// 3. 发送请求获取结果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);

long value = response.getHits().getTotalHits().value;
System.out.println("查询到的结果条数为:" + value + "条。");

// 4. 解析结果
SearchHit[] hits = response.getHits().getHits();
// 遍历解析封装
for (SearchHit hit : hits)
// 4.1 获取hotelDoc对象
HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), HotelDoc.class);
// 4.2 处理高亮
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (!CollectionUtils.isEmpty(highlightFields))
// 4.2.1 获取高亮字段结果
HighlightField highlightField = highlightFields.get("name");
if (highlightField != null)
// 4.2.2 取出高亮结果数组中的第一个元素,就是酒店名称
String name = highlightField.getFragments()[0].toString();
hotelDoc.setName(name);


// 5. 打印结果
System.out.println(hotelDoc);

【Elasticsearch-Query


7、距离排序


// 2.3 距离排序
String location = params.getLocation();
if (location != null && !"".equals(location))
request.source().sort(SortBuilders
.geoDistanceSort("location", new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);

【Elasticsearch-Query


8、组合查询


// 2. 算分控制
FunctionScoreQueryBuilder functionScoreQuery =
QueryBuilders.functionScoreQuery(
// 原始查询,相关性算分的查询
boolQuery,
// function score的数组
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]
// 其中的一个function score元素
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
// 过滤条件
QueryBuilders.termQuery("isAD", true),
// 算分函数:权重算分相乘
ScoreFunctionBuilders.weightFactorFunction(10)
)
);
request.source().query(functionScoreQuery);

【Elasticsearch-Query


四、结尾

以上即为Query DSL的部分内容


谈谈 DSL 以及 DSL 的应用(以 CocoaPods 为例)

最近在公司做了一次有关 DSL 在 iOS 开发中的应用的分享,这篇文章会简单介绍这次分享的内容。

因为 DSL 以及 DSL 的界定本身就是一个比较模糊的概念,所以难免有与他人观点意见相左的地方,如果有不同的意见,我们可以具体讨论。

这次文章的题目虽然是谈谈 DSL 以及 DSL 的应用,不过文章中主要侧重点仍然是 DSL,会简单介绍 DSL 在 iOS 开发中(CocoaPods)是如何应用的。

没有银弹?

1987 年,IBM 大型电脑之父 Fred Brooks 发表了一篇关于软件工程中的论文 No Silver Bullet—Essence and Accidents of Software Engineering 文中主要围绕这么一个观点:没有任何一种技术或者方法能使软件工程的生产力在十年之内提高十倍。

There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.

时至今日,我们暂且不谈银弹在软件工程中是否存在(这句话在老板或者项目经理要求加快项目进度时,还是十分好用的),作为一个开发者也不是很关心这种抽象的理论,我们更关心的是开发效率能否有实质的提升。

今天要介绍的 DSL 就可以真正的提升生产力,减少不必要的工作,在一些领域帮助我们更快的实现需求。

DSL 是什么?

笔者是在两年以前,在大一的一次分享上听到 DSL 这个词的,但是当时并没有对这个名词有多深的理解与认识,听过也就忘记了,但是最近做的一些开源项目让我重新想起了 DSL,也是这次分享题目的由来。

DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证,而是 General Purpose Language 的简称,即通用编程语言,也就是我们非常熟悉的 Objective-C、Java、Python 以及 C 语言等等。

Wikipedia 对于 DSL 的定义还是比较简单的:

A specialized computer language designed for a specific task.

为了解决某一类任务而专门设计的计算机语言。

与 GPL 相对,DSL 与传统意义上的通用编程语言 C、Python 以及 Haskell 完全不同。通用的计算机编程语言是可以用来编写任意计算机程序的,并且能表达任何的可被计算的逻辑,同时也是 图灵完备 的。

这一小节中的 DSL 指外部 DSL,下一节中会介绍 内部 DSL/嵌入式 DSL

但是在里所说的 DSL 并不是图灵完备的,它们的表达能力有限,只是在特定领域解决特定任务的。

A computer programming language of limited expressiveness focused on a particular domain.

另一个世界级软件开发大师 Martin Fowler 对于领域特定语言的定义在笔者看来就更加具体了,DSL 通过在表达能力上做的妥协换取在某一领域内的高效。

而有限的表达能力就成为了 GPL 和 DSL 之间的一条界限。

几个栗子

最常见的 DSL 包括 Regex 以及 HTML & CSS,在这里会对这几个例子进行简单介绍

  • Regex

    • 正则表达式仅仅指定了字符串的 pattern,其引擎就会根据 pattern 判断当前字符串跟正则表达式是否匹配。

      谈谈 DSL 以及 DSL 的应用(以 CocoaPods 为例)

  • SQL

    • SQL 语句在使用时也并没有真正的执行,我们输入的 SQL 语句最终还要交给数据库来进行处理,数据库会从 SQL 语句中读取有用的信息,然后从数据库中返回使用者期望的结果。

  • HTML & CSS

    • HTML 和 CSS 只是对 Web 界面的结构语义和样式进行描述,虽然它们在构建网站时非常重要,但是它们并非是一种编程语言,正相反,我们可以认为 HTML 和 CSS 是在 Web 中的领域特定语言。

Features

上面的几个

以上是关于Elasticsearch-Query DSL的主要内容,如果未能解决你的问题,请参考以下文章

ES DSL语法

ElasticSearch02_DSL特定语言matchbooltermtermsaggsfromsizerangesort排序查询

ElasticSearch02_DSL特定语言matchbooltermtermsaggsfromsizerangesort排序查询高亮显示

ElasticSearch02_DSL特定语言matchbooltermtermsaggsfromsizerangesort排序查询高亮显示

ElasticSearch02_DSL特定语言matchbooltermtermsaggsfromsizerangesort排序查询高亮显示

商城项目17_es的DSL特定语言matchbooltermtermsaggsfromsizerangesort排序查询高亮显示