esjavaor的简单介绍

博主:adminadmin 2022-12-06 07:03:05 65

今天给各位分享esjavaor的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

Es实现百万级数据快速检索

在用户点击一篇采购文章,会匹配到该文章全部相关内容。所有数据是存在ES中的,百万量级。恩~要用python写一个接口。通过查找资料,通过 ES模糊搜索 可以实现。

prefix的匹配一般是处理不分词的场景,将会匹配articleID中以”J”开头的doc。prefix不会计算revelance score,只是作一个过滤的操作,和filter唯一的区别是filter会缓存结果,而prefix不会。前缀越短要处理的doc越多,性能越差。

?会匹配任意字符,*会匹配0个或多个字符。性能根prefix一样差,必须要扫描整个倒排索引。

[0-9]:指定范围内的数字

[a-z]:指定范围内的字幕

.:一个字符

+:前面的正则表达式可以出现一次或多次

正则的搜索同样会扫描全表,性能也会很差

fuzziness参数调整纠正的次数

通常不会直接用上述搜索,而会用下面的搜索:

在es中,使用组合条件查询是其作为搜索引擎检索数据的一个强大之处,在前几篇中,简单演示了es的查询语法,但基本的增删改查功能并不能很好的满足复杂的查询场景,比如说我们期望像mysql那样做到拼接复杂的条件进行查询该如何做呢?es中有一种语法叫bool,通过在bool里面拼接es特定的语法可以做到大部分场景下复杂条件的拼接查询,也叫复合查询

首先简单介绍es中常用的组合查询用到的关键词,

filter:过滤,不参与打分

must:如果有多个条件,这些条件都必须满足 and与

should:如果有多个条件,满足一个或多个即可 or或

must_not:和must相反,必须都不满足条件才可以匹配到 !非

发生 描述

must

该条款(查询)必须出现在匹配的文件,并将有助于得分。

filter

子句(查询)必须出现在匹配的文档中。然而不像 must查询的分数将被忽略。Filter子句在过滤器上下文中执行,这意味着评分被忽略,子句被考虑用于高速缓存。

should

子句(查询)应该出现在匹配的文档中。如果 bool查询位于查询上下文中并且具有mustor filter子句,则bool即使没有should查询匹配,文档也将匹配该查询 。在这种情况下,这些条款仅用于影响分数。如果bool查询是过滤器上下文 或者两者都不存在,must或者filter至少有一个should查询必须与文档相匹配才能与bool查询匹配。这种行为可以通过设置minimum_should_match参数来显式控制 。

must_not

子句(查询)不能出现在匹配的文档中。子句在过滤器上下文中执行,意味着评分被忽略,子句被考虑用于高速缓存。因为计分被忽略,0所有文件的分数被返回。

下面用实验演示一下上述查询的相关语法,

1、首先,我们创建一个索引,并且在索引里添加几条数据,方便后面使用,

我这里直接批量插入数据,也可以通过PUT的语法单条执行插入,

POST /forum/article/_bulk

{ "index": { "_id": 1 }}

{ "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2019-07-01","title":"java contains hadoop and spark","topic":"java" }

{ "index": { "_id": 2 }}

{ "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2019-07-02",title":"php contains admin","topic":"java and php" }

{ "index": { "_id": 3 }}

{ "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2019-07-03" ,title":"spark is new language","topic":"spark may use java"}

{ "index": { "_id": 4 }}

{ "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2019-07-04" ,title":"hadoop may involve java","topic":"big data used"}

或者使用put语法

PUT /forum/article/4

{

"articleID": "QQPX-R-3956-#aD8",

"userID": 2,

"hidden": true,

"postDate": "2019-07-04",

"title": "hadoop may involve java",

"topic": "big data used"

}

4条数据插入成功,

2、termQuery,term查询不分词,类似于mysql的where filedName = ? 语法,即精准匹配,比如我们查询articleID = XHDK-A-1293-#fJ3的这条数据,

GET /forum/article/_search

{

"query": {

"term": {

"articleID.keyword":"XHDK-A-1293-#fJ3"

}

}

}

2、must查询,即查询的条件中必须匹配的字段,例如,查询title中必须包含java的数据,

GET /forum/article/_search

{

"query": {

"bool": {

"must": [

{"term":{"title":"hadoop"}}

]

}

}

}

查出两条数据

如果是should呢?如下语法,即查询title中包含hadoop或者topic中包含spark,二者满足其一即可,

GET /forum/article/_search

{

"query": {

"bool": {

"should": [

{"term":{"title":"hadoop"}},

{"term": {"topic": "spark"}}

]

}

}

}

查询出3条数据,

must和should结合使用,

最后再来一个比较复杂的嵌套查询,我们先看一下这条sql语句,

select *

from forum.article

where article_id=‘XHDK-A-1293-#fJ3’

or (article_id=‘JODL-X-1937-#pV7’ and post_date=‘2017-01-01’),

对应着转化为es的复合查询语法是怎样的呢?拆分来看,就是一个should语句的嵌套,

GET /forum/article/_search

{

"query": {

"bool": {

"should": [

{

"term": {

"articleID.keyword": "XHDK-A-1293-#fJ3"

}

},

{

"bool": {

"must": [

{

"term": {

"articleID.keyword":"JODL-X-1937-#pV7"

}

},

{

"term": {

"postDate":"2019-07-01"

}

}

]

}

}

}

}

查询到一条结果,按照这种思路,如果我们对一个复杂的查询不知道如何构建查询语句时,可以考虑先按照sql的语法进行拆分,然后再组织es查询语句是个不错的突破口,

到这里,可能我们会有疑问,复合条件中的term查询和单纯的match区别在哪里呢?既然都是查询,究竟原理有何不同呢?

我们知道match query是需要全文检索的,是进行full text的全文检索,当然如果搜索的字段值做了not_analyzed,match query也相当于是term query了,比如下面这个搜索,由于在插入数据的时候我们没有对title这个字段进行规定,默认就是text类型的,会被自动分词,这样查询的时候只要title中包含了 hadoop,就可以匹配到,

GET /forum/article/_search

{

"query": {

"match": {

"title": "hadoop"

}

}

}

2、有些情况下,假如我们直接使用match进行查询,又希望查出来的结果尽可能是我们期望的包含更多关键词的结果,则在match进行匹配的时候可以添加其他的条件,以便提升结果的匹配精确度,

GET /forum/article/_search

{

"query": {

"match": {

"title": {

"query": "java hadoop",

"operator": "and"

}

}

}

}

这样匹配出来的结果包含了更多我们期望的关键词,即query中可以指定我们查询的结果中包含的关键词,

es还有其他的语法达到上述的效果,minimum_should_match ,通过这个语法,可以指定匹配的百分数,就是查询的关键词至少要达到的百分数,下面这个表示全部匹配,只查询到一条结果,

假如我们将百分数调低点,比如75%,可以看到查到两条结果,

3、当然,我们也可以将bool和match结合起来使用,如下,

GET /forum/article/_search

{

"query": {

"bool": {

"must": [

{"match": {"title": "java"}}

],

"must_not": [

{ "match": { "title": "spark"}}

]

, "should": [

{

"match": {

"title": "php"

}

}

]

}

}

}

通过这种方式,也可以达到更精准的匹配我们期望的查询结果,

简单总结来说,当我们使用match进行查询的时候,如果查询的field包含多个词,比如像下面这个,

{

"match": { "title": "java elasticsearch"}

}

其实es会在底层自动将这个match query转换为bool的语法bool should,指定多个搜索词,同时使用term query,则转化后的语法如下,

{

"bool": {

"should": [

{ "term": { "title": "java" }},

{ "term": { "title": "elasticsearch" }}

]

}

}

而上面所说的match中加and的查询,对应于bool查询,转化后为 term+must 的语法如下,

{

"match": {

"title": {

"query": "java elasticsearch",

"operator": "and"

}

}

}

{

"bool": {

"must": [

{ "term": { "title": "java" }},

{ "term": { "title": "elasticsearch" }}

]

}

}

对于minimum_should_match这种语法来说,道理类似,

{

"match": {

"title": {

"query": "java elasticsearch hadoop spark",

"minimum_should_match": "75%"

}

}

}

{

"bool": {

"should": [

{ "term": { "title": "java" }},

{ "term": { "title": "elasticsearch" }},

{ "term": { "title": "hadoop" }},

{ "term": { "title": "spark" }}

],

"minimum_should_match": 3

}

}

我们来看一个具体的操作实例,也就是说必须至少包含3个关键词的数据才会出现在搜索结果中,

3、在搜索中,我们有这样一种需求,期望搜索的结果中包含java 如果标题中包含hadoop或spark就优先搜索出来,同时呢,如果一个帖子包含java hadoop,一个帖子包含java spark,包含hadoop的帖子要比spark优先搜索出来,

对于这样的需求,通俗来讲,就是需要通过增大某些搜索条件的权重,从而在搜索的结果中,更多符合和满足我们业务场景的数据靠前搜索出来,在es中可以通过boost关键词来增加搜索条件的权重,

GET /forum/article/_search

{

"query": {

"bool": {

"must": [

{

"match": {

"title": "java"

}

}

],

"should": [

{

"match": {

"title": {

"query": "hadoop"

}

}

},

{

"match": {

"title": {

"query": "spark",

"boost":2

}

}

},

{

"match": {

"title": {

"query": "php"

}

}

},

{

"match": {

"title": {

"query": "hadoop",

"boost": 5

}

}

}

]

}

}

}

上面这个例子意思是我们赋予搜索的title中包含hadoop的条件权重更大,hadoop的结果会有限被搜索出来

4、dis_max语法,也叫best_field,在某些情况下,假如我们在bool查询中用多个字段进行查询,但是查询一样,就可能导致说查询出来的结果并不是按照我们期望的那个字段将其排在前面,也就是说,我们只需要包含指定字段的内容展示在前面,如下,

GET /forum/article/_search

{

"query": {

"bool": {

"should": [

{ "match": { "title": "java solution" }},

{ "match": { "content": "java solution" }}

]

}

}

}

title和content的搜索条件相同,但我们希望的是结果中title 包含java solution的靠前展示,但直接这样查询可能达不到预期的效果,如果使用dis_max进行拼接就可以了,

GET /forum/article/_search

{

"query": {

"dis_max": {

"queries": [

{ "match": { "title": "java solution" }},

{ "match": { "content": "java solution" }}

]

}

}

}

通过这样的方式,使得查询的结果更符合预期值,

5、但是使用dis_max,只取某一个query最大的分数,完全不考虑其他query的分数,即假如说某个结果中包title含了java,但topic中没有包含java,另一却是相反,还有的结果是两者都包含java,在dis_max语法下,只会拿到相关度得分最高的那一个,而不会考虑其他的结果,这时,如果需要获取其他的title或者topic包含java的结果,可以使用tie_breaker进一步包装,如下,

GET /forum/article/_search

{

"query": {

"dis_max": {

"queries": [

{ "match": { "title": "spark" }},

{ "match": { "topic": "java"}}

],

"tie_breaker": 0.6

}

}

}

这样查到3条结果,综合来说,最终还是需要结合实际业务场景进行使用,但是在大多数情况相爱,我们还是希望搜索的结果中是按照我们给定的条件包含更多的关键词的内容被优先搜索出来,

09 ES的document路由原理,写一致性,读取以及增删改等请求的原理

本节主要深入一些原理型的知识,包括document路由原理,写一致性,读取以及增删改等请求的原理

(1)document路由到shard上是什么意思?

一个index的数据会被分为多个shard中。所以说一个document,只能存在于一个shard中。当客户端创建document的时候,es此时就需要决定这个document是放在这个index的哪个shard上。这个过程,就称之为document routing,即数据路由。

(2)路由算法:shard = hash(routing) % number_of_primary_shards

举个例子,一个index有3个primary shard,P0,P1,P2

每次增删改查一个document的时候,都会带过来一个routing number,默认就是这个document的id(可能是手动指定,也可能是自动生成)ES会将这个routing值,传入一个hash函数中,产出一个routing值的hash值,hash(routing) = 21。然后将hash函数产出的值对这个index的primary shard的数量求余数,21 % 3 = 0。ES就把这个document就放在P0上。(由这个就可以知道primary_shards的数量为什么是固定的了)

(3)手动指定routing: _id or custom routing value

默认的routing就是_id,也可以在发送请求的时候,手动指定一个routing,比如说

具体操作参见官方文档

_routing field | Elasticsearch Reference [7.6] | Elastic

手动指定routing value是很有用的,可以保证说,某一类document一定被路由到一个shard上去,那么在后续进行应用级别的负载均衡,以及提升批量读取的性能的时候,是很有帮助的

(1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)

(2)coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)

(3)实际的node上的primary shard处理请求,然后将数据同步到replica node

(4)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端

consistency已经废弃了。

使用 wait_for_active_shards进行设置,默认值为1,即只要求主分片处于活动状态, 还可以设置为2,3等,就是大于0,小于number_of_replicas+1的正整数。

wait_for_active_shards=all表示number_of_replicas+1,即该索引所有分片的总数。

具体说明参见官方文档:

Index API | Elasticsearch Reference [7.6] | Elastic

1、客户端发送请求到任意一个node,成为coordinate node

2、coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡

3、接收请求的node返回document给coordinate node

4、coordinate node返回document给客户端

5、特殊情况:document如果还在建立索引过程中,可能只有primary shard有,任何一个replica shard都没有,此时可能会导致无法读取到document,但是document完成索引建立之后,primary shard和replica shard就都有了

1、bulk中的每个操作都可能要转发到不同的node的shard去执行

2、如果采用比较良好的json数组格式

允许任意的换行,整个可读性非常棒,读起来很爽,es拿到那种标准格式的json串以后,要按照下述流程去进行处理

(1)将json数组解析为JSONArray对象,这个时候,整个数据,就会在内存中出现一份一模一样的拷贝,一份数据是json文本,一份数据是JSONArray对象

(2)解析json数组里的每个json,对每个请求中的document进行路由

(3)为路由到同一个shard上的多个请求,创建一个请求数组

(4)将这个请求数组序列化

(5)将序列化后的请求数组发送到对应的节点上去

3、耗费更多内存,更多的jvm gc开销

我们之前提到过bulk size最佳大小的那个问题,一般建议说在几千条那样,然后大小在10MB左右,所以说,可怕的事情来了。假设说现在100个bulk请求发送到了一个节点上去,然后每个请求是10MB,100个请求,就是1000MB = 1GB,然后每个请求的json都copy一份为jsonarray对象,此时内存中的占用就会翻倍,就会占用2GB的内存,甚至还不止。因为弄成jsonarray之后,还可能会多搞一些其他的数据结构,2GB+的内存占用。占用更多的内存可能就会积压其他请求的内存使用量,比如说最重要的搜索请求,分析请求,等等,此时就可能会导致其他请求的性能急速下降.

另外的话,占用内存更多,就会导致java虚拟机的垃圾回收次数更多,跟频繁,每次要回收的垃圾对象更多,耗费的时间更多,导致es的java虚拟机停止工作线程的时间更多

4、现在的奇特格式

(1)不用将其转换为json对象,不会出现内存中的相同数据的拷贝,直接按照换行符切割json

(2)对每两个一组的json,读取meta,进行document路由

(3)直接将对应的json发送到node上去

5、最大的优势在于,不需要将json数组解析为一个JSONArray对象,形成一份大数据的拷贝,浪费内存空间,尽可能地保证性能

膜拜一下大神的文章:

Day1: 大规模Elasticsearch集群管理心得 - Elastic 中文社区

elasticsearch 用java client 多个and or 条件 怎么写

我刚刚特意写的,用2个Map作为传参,一个是must,一个是should。代码如下:

//创建查询

SearchRequestBuilder srb = client.prepareSearch(INDEX);

srb.setTypes(ASK_TYPE);

srb.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);

//分页

srb.setFrom((pageNo - 1) * pageSize).setSize(pageSize);

//按时间倒序

SortBuilder sortBuilder = SortBuilders.fieldSort("date").order(SortOrder.DESC);

srb.addAggregation(aggregation);//聚合

srb.addSort(sortBuilder);//排序

/**********************主要看这里 start*********************************/

if(null != mustMap  mustMap.size()  0){

//创建一个查询

BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

//这里查询的条件用map传递

for(String key : mustMap.keySet()){

queryBuilder.must(QueryBuilders.termQuery(key,mustMap.get(key)));

}

//这里查询的条件用map传递

for(String key : shouldMap.keySet()){

queryBuilder.should(QueryBuilders.termQuery(key,mustMap.get(key)));

}

//查询

srb.setQuery(queryBuilder);

}

/**********************主要看这里 end*********************************/

//请求

SearchResponse response = srb.get();

//更多看这里:

esjavaor的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、esjavaor的信息别忘了在本站进行查找喔。

The End

发布于:2022-12-06,除非注明,否则均为首码项目网原创文章,转载请注明出处。