Elasticsearch Query DSL之Term level queries

分析:使用term_query,并且采用查询字符串foxes,由于full_text是text字段类型,会先进行分词,故会存入quick、foxes两个词根,与输入字符串foxes匹配,故结论为能匹配到文档。

查询示例4:

GET my_index/_search

{

“query”: {

“match”: {

“full_text”: “Quick Foxes!”

}

}

}

分析:使用match query(权威搜索),会首先对查询字符串进行分词,然后根据词根一一匹配,故该结果能匹配到文档。

2、terms query


查找包含指定字段中包含查询词根集合中任意一个精确匹配的文档。实例如下:

GET /_search

{

“query”: {

“terms” : { “user” : [“kimchy”, “elasticsearch”]}

}

}

其查询的意图:查询"user"属性的值为"kimchy"或"elasticsearch"的文档。

2.1 terms 查询机制

试想如下一个场景,在微博应用场景中,需要查看关注你的所有用户发布的微博,那这个查询第一步应该是得到关注你的所有用户列表,然后查询微博的发布者ID在关注你的列表集合中的所有文档。这个关注列表一般不会很小,如果要分两步来实现的话,查询中传入的terms这个集合会很大,相当于关系型数据库中的in (很大的集合),那有没有一种机制,支持类似关系型数据库中 a.id in ( select b.id from B b where …)这种方式呢?答案当然是有的。 下面下能给出本次试验的基础数据:

PUT /users/_doc/2

{

“followers” : [“1”, “3”]

}

PUT /tweets/_doc/1

{

“user” : “1”

}

//其查询写法如下:

GET /tweets/_search

{

“query” : {

“terms” : {

“user” : {

“index” : “users”,

“type” : “_doc”,

“id” : “2”,

“path” : “followers”

}

}

}

}

查询terms支持如下参数:

  • index 指定查询索引名(相当于关系型数据库database)

  • type 指定类型名(相当于关系型数据库table)

  • id 指定文档的id(相当于关系型数据库的row 主键id)

  • path:值来自哪个字段,支持级联,例如followers.id等嵌套json属性。

  • routing:指定路由字段值。

从上可知,terms过滤器的值将从具有指定类型的索引中的指定id的文档中的字段中获取。在内部执行get请求以从指定路径(_source字段中存储的值)中提取。

使用大量词根执行terms查询请求可能相当缓慢,因为每个词根都需要额外的处理和占用内存。为了防止出现这种情况,可以设置最大支持的terms的个数,默认为65536。可以通过设置index.max_terms_count来更改此默认值。

2.2 java(Demo示例)

public static void testTermsQuery() {

RestHighLevelClient client = EsClient.getClient();

try {

SearchRequest searchRequest = new SearchRequest();

searchRequest.indices(“esdemo”);

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

sourceBuilder.query(

QueryBuilders.termsQuery(“context”, “fox”, “brown”)

);

// TermsLookup termsLookup = new TermsLookup(“esdemo”, “matchquerydemo”, “1”, “context”);

// termsLookup.routing(“1”);

// sourceBuilder.query(

// QueryBuilders.termsLookupQuery(“context”, termsLookup);

// );

searchRequest.source(sourceBuilder);

SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);

System.out.println(result);

} catch (Throwable e) {

e.printStackTrace();

} finally {

EsClient.close(client);

}

}

3、terms_set query


查找与一个或多个指定词根相匹配的文档。必须匹配的项的数量取决于指定的最小值或脚本。必须匹配的项的数量根据每个文档的不同而不同,并且由最小值控制的项应该匹配字段,或者由最小值计算的每个文档应该匹配脚本,先从示例开始讲起:

PUT /my-index

{

“mappings”: {

“_doc”: {

“properties”: {

“required_matches”: {

“type”: “long”

}

}

}

}

}

首先为_doc类型新增一个数值型的字段,这里取值为required_matches。

PUT /my-index/_doc/1?refresh

{

“codes”: [“ghi”, “jkl”],

“required_matches”: 2

}

PUT /my-index/_doc/2?refresh

{

“codes”: [“def”, “ghi”,“test”,“ak”],

“required_matches”: 3

}

在存入es中,会自己决定需要匹配的词根个数,低于这个数值,则不会返回该文档。

GET /my-index/_search

{

“query”: {

“terms_set”: {

“codes” : {

“terms” : [“abc”, “def”, “ghi”],

“minimum_should_match_field”: “required_matches”

}

}

}

}

通过属性minimum_should_match_field指定需要匹配的个数,但这个数值来源于文档内部的字段,故该属性值就是指定匹配个数的来源属性名称。该查询结构也支持脚本,其脚本指定字段为minimum_should_match_script,关于script脚本将会在专门的章节中讲述。

4、range query


范围查询。查询的类型取决于字段类型,对于string字段,是TermRangeQuery,而对于number/date字段,查询是NumericRangeQuery。以下示例返回年龄在10到20岁之间的所有文档。

GET _search

{

“query”: {

“range” : {

“age” : {

“gte” : 10,

“lte” : 20,

“boost” : 2.0

}

}

}

}

range query支持如下参数:

  • gte 大于等于

  • gt 大于

  • lte 小于等于

  • lt 小于

  • boost 权重(重要程度)

4.1 data maths(日期函数)

日期表达式以一个日期(基准日期,锚定日期)开始,可以是now,也可以是以||结尾的日期字符串。这个锚定日期可以有选择地跟随一个或多个数学表达式,例如:

  • +1h 增加一小时

  • -1d 减少一天

  • /d - 向日取整 (返回该天的整点)

  • /M -向月取整(返回该月的第一天的整点)

日期支持如下时间单位:

  • y 年

  • M 月

  • w 周

  • d 日

  • h 小时(12表示法)

  • H 小时(24表示法)

  • m 分钟

  • s 小时

假设现在是2001-01-01 12:00:00,以下是一些例子:

1、now+1h

当前时间加1小时,最终表示为:2001-01-01 13:00:00

2、now-1h

当前时间减1小时,最终表示为:2001-01-01 11:00:00

3、now-1h/d

先减去一小时,为2001-01-01 11:00:00,然后舍弃d后面的时间,这里是舍弃11:00:00,故最终表示为2001-01-01 00:00:00

4、2001.02.01||+1M/d

2001-02-01先加一个月,变为2001-03-01,然后舍弃天后的实际,最终表示为2001-03-01 00:00:00

4.2 日期类型范围查询示例(使用date maths)

GET _search

{

“query”: {

“range” : {

“date” : {

“gte” : “now-1d/d”,

“lt” : “now/d”

}

}

}

}

例如当前时间为2018-10-24 12:25:35,则代表查询的含义为date字段的值大于等于2018-10-23 00:00:00 小于 2018-10-24 00:00:00。

当使用日期数学将日期四舍五入到最近的日、月、小时等时,四舍五入的日期取决于范围的两端是否包含或排除。舍入移动到舍入范围的最后一毫秒,舍出到舍入范围的第一毫秒。关于各运算符的舍入舍出规则如下:

  • gt

2014-11-18||/M becomes 2014-11-30T23:59:59.999, 使用gt(不包含e),是向上,取当月最后一天23:59:59

  • gte

2014-11-18||/M becomes 2014-11-01,如果运算符为大于等于,则向下舍弃,取当月第一天零点

  • lt

2014-11-18||/M becomes 2014-11-01,如果运算算法小于,则向下舍弃

  • lte

2014-11-18||/M becomes 2014-11-30T23:59:59.999, 小于等于,则向上,取当月最后一天的23:59:59

4.3 日期类型范围查询示例(使用日期格式转换)

GET _search

{

“query”: {

“range” : {

“born” : {

“gte”: “01/01/2012”,

“lte”: “2013”,

“format”: “dd/MM/yyyy||yyyy”

}

}

}

}

format使用 双竖线|| 做分隔符号,上面表示,查询born字段 大于等于2012-01-01 00:00:00 小于等于2013-01-01 00:00:00。

如果需要年月日,消息分钟,请用如下写法:

QueryBuilders.rangeQuery(“post_date”)

.gte(“2018-10-25T14:12:10”)

.lte(“2018-10-27T14:12:10”)

.format(“yyyy-MM-dd’T’HH:mm:ss||yyyy-MM-dd’T’HH:mm:ss”)。// ‘T’用来分隔 年月日 与 时分秒。

5、exists query


返回指定字段中至少有一个非空值(null)的文档。示例如下:

GET /_search

{

“query”: {

“exists” : { “field” : “user” }

}

}

对于上面的查询,下面的所有文档都将符合要求:

{ “user”: “jane” }

{ “user”: “” } // 空字符串不为null

{ “user”: “-” }

{ “user”: [“jane”] }

{ “user”: [“jane”, null ] } //因为存在jane值不为null,则匹配。

5.1 null_value映射

自定义null值。例如将"null"字符串定义为null值。

PUT /example

{

“mappings”: {

“_doc”: {

“properties”: {

“user”: {

“type”: “keyword”,

“null_value”: “null

}

}

}

}

}

其作用是会将user字段的null值索引为_null_字符串,则下面的文档将能被exists匹配:

{ “user”: null }

{ “user”: [null] }

5.2 查询不存在某个字段的文档

GET /_search

{

“query”: {

“bool”: {

“must_not”: {

“exists”: {

“field”: “user”

}

}

}

}

}

查询不存在属性user的文档。

6、prefix query


词根前缀查询,对查询词根不会使用分词器进行分词。使用示例如下:

GET /_search

{ “query”: {

“prefix” : { “user” : “ki” }

}

}

同样,也可以未字段设置权重(boost)。示例如下:

GET /_search

{ “query”: {

“prefix” : { “user” : { “value” : “ki”, “boost” : 2.0 } }

}

}

其代表含义可转换为关系型数据库查询语句:where a.user like ‘ki%’。

思考一下,如果存在有文档的user字段的值为"Kimmi",使用如下字符查询条件:

{ “query”: {

“prefix” : { “user” : “Ki” }

}

}

该查询能匹配到结果吗?在默认使用标准分词器的环境中,是无法匹配到数据的,其原因如下:首先,在存储文档时,首先会对"kimmi"字段进行分词,返回的词根为kimmi(全小写),将这些词根存入到Elasticsearch(lucene)的倒排索引中,然后进行查询时,并不会使用分词器对 prefix进行分词,故查询字符串为Ki,是无法匹配到上述文档的,要向匹配到文档,请使用小写的查询ki。这也是ES中的term(词根精确查询)与关系型数据库的一个非常重要的区别。

JAVA代码查询示例:

public static void testTermQuery_prefix() {

RestHighLevelClient client = EsClient.getClient();

try {

SearchRequest searchRequest = new SearchRequest();

searchRequest.indices(“twitter”);

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

sourceBuilder.query(

QueryBuilders.prefixQuery(“user”, “ki”)

.boost(2.0f)

);

searchRequest.source(sourceBuilder);

SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);

System.out.println(result);

} catch (Throwable e) {

e.printStackTrace();

} finally {

EsClient.close(client);

}

}

最后

小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。

关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。

image

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!
例:

public static void testTermQuery_prefix() {

RestHighLevelClient client = EsClient.getClient();

try {

SearchRequest searchRequest = new SearchRequest();

searchRequest.indices(“twitter”);

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

sourceBuilder.query(

QueryBuilders.prefixQuery(“user”, “ki”)

.boost(2.0f)

);

searchRequest.source(sourceBuilder);

SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);

System.out.println(result);

} catch (Throwable e) {

e.printStackTrace();

} finally {

EsClient.close(client);

}

}

最后

小编利用空余时间整理了一份《MySQL性能调优手册》,初衷也很简单,就是希望能够帮助到大家,减轻大家的负担和节省时间。

关于这个,给大家看一份学习大纲(PDF)文件,每一个分支里面会有详细的介绍。

[外链图片转存中…(img-NYc0g9aI-1719155727251)]

这里都是以图片形式展示介绍,如要下载原文件以及更多的性能调优笔记(MySQL+Tomcat+JVM)!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值