专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

ElasticSearch使用总结

针对目前工作每日处理上亿数据的经历,作了几点总结


增删改查

  • 增用put(除了自动生成ID的创建文档)
  • 删用delete
  • 改用post
  • 查用get
  • URL只要是加下划线的,都用POST请求

分词查询

term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇,那么设置索引mapping时,需要注意:是否需要对term查询的字段设置不进行分析,类如:

"name": {
    "type":  "string",
    "index": "not_analyzed"
}

那么”name”: “Quick Foxes!”内容被存放到索引中将变成[quick, foxes],即进行了分词。那么使用term查询Quick Foxes将不能查到该结果。另外,5.6.8之后,分词not_analyzed改为用keyword代替

搜索格式

  • ip:port/index/type/_search,表示在该index的type中搜索;
  • ip:port/index/_search,表示在该index中搜索;
  • ip:port/_search,表示在全文搜索;

settings vs mappings

  • settings是修改分片和副本数的。
  • mappings是修改字段和类型的。

?pretty作用

URL后加上?pretty表示将返回的json进行格式化,这时解析注意\n

副本与分片

不存在索引时,可以指定副本和分片(不指定默认是5分片,1副本),如果已经存在,则只能修改副本。

操作setting

  • 操作不存在索引:
curl -XPUT '192.168.80.10:9200/liuch/' -d
    '{"settings":{"number_of_shards":3,"number_of_replicas":0}}'

  • 操作已存在索引:
curl -XPUT '192.168.80.10:9200/zhouls/_settings' -d
    '{"index":{"number_of_replicas":1}}'

操作mapping

  • 操作不存在的索引:
curl -XPUT '192.168.80.10:9200/zhouls' -d
    '{"mappings":{"emp":{"properties":{"name":{"type":"string","analyzer": "ik_max_word"}}}}}'

  • 操作已存在的索引:
curl -XPOST http://192.168.80.10:9200/zhouls/emp/_mapping -d
    '{"properties":{"name":{"type":"string","analyzer": "ik_max_word"}}}'

ES后面参数:

  • p=param:请求参数方式
  • 空格 -d body:请求体方式
  • v:输出详细
  • h=字段1,字段2:只输出该字段
  • filter_path(如:hits.hits._source.username):只返回指定path的字段,高版本支持设置”_source”:[”username”,”pass”]
  • search_type=count:任何时候都不返回hits部分,减少返回内容,只计数(注意,5版本之后已移除该设置)
  • refresh:时刻刷新,为了实时获取最新数据,默认刷新间隔为1秒

size

size设置为0,表示不返回文档的信息,一般用在聚合操作,在只关心聚合的结果而不关心查询结果的情况下使用。

Scroll查询示例:

首次:

ip:port/index/_search?scroll=1m
{
    "size":10
}

之后:

ip:port/_search/scroll    //注意此处没有了index,scroll格式也变化了
{
    //注意此处没有了size
    "scroll":1m,
    "scroll_id":"上次查询返回的_scroll_id"
}

ID特殊字符

如果根据ID搜索文档时,ID含有特殊字符,如\、/等,可以先用URLEncoder进行编码,编码后仍然查询有效

Term vs Terms

  • 对于查询多个字段,用Terms,而单个字段要用Term
  • 对于排序和script应该用Terms
  • 对于聚合分组,用Terms

Terms查询数组长度过大问题

14、ElasticSearch使用terms查询时,如果值为数组且长度大于1024,可能出现:【maxclauseCount is set to 1024】错误,可以使用filter来解决

"query":{
    "bool":{
        "must":{
            "match_all":{}
        },
    "filter":{
        "terms":{
            "dip":["0.0.0.0",……]
        }
    }
}

Scroll + Scan

使用scroll搜索时,首次搜索和之后的搜索都会返回hit,但是如果加入了scan,需注意

  • 首次不会返回hit,只会返回_scroll_id,然后第二次才开始返回值
  • 比如设置size=1000,则实际返回的数量是size*分片数
  • scanning scroll 查询不支持聚合
  • scanning scroll 查询结果没有排序,结果的顺序是doc入库时的顺序

聚合中的size

聚合中,使用terms分组默认返回每个组的10条数组,如果需要返回所有数据,在terms内添加字段:"size":0,当然也可以指定返回需要的长度的数据

但是注意:size为0是早期版本,0代表全部;5.x,6.x都不允许为0了。那么对于5.x和6.x设置为全量聚合:"size":2147483647

Restclient 查询数据过大

使用restclient,查询数据过大,报:entity content is too long xxxx for the configured buffer limit 104857600

//Overiding the 100MB Buffer Limit to 1GB
HttpEntity entity=new NStringEntity(params,ContentType.APPLICATION_JSON);
response = client.performRequest("POST", endPoint, new HashMap<>(), entity, new HeapBufferedResponseConsumerFactory(1024 * 1024 * 1024));

**注意:**es rest clent依赖包版本需要5.6以上才能使用HeapBufferedResponseConsumerFactory

广度优先聚合

在海量数据下使用聚合嵌套聚合导致ES崩溃:考虑使用广度优先聚合:

{ "aggs" :
    { "actors" :
        { "terms" :
            { "field" :"actors" ,"size" :10 ,"collect_mode":"breadth_first"
…………

注意:广度优先聚合的内存要求与修剪前每个桶中的文档数量成线性关系,如果每个桶中的文档有数千或数十万,也不考虑使用广度优先。这也是为什么深度优先是默认选择的原因。

_source vs doc

script使用_source[’key’]速度比doc[’key’].value慢。对于上亿数据,实测_source 8秒,doc 0.8秒。

注意:

  • es低版本:doc[’key’].value _source[’key’]
  • es高版本:doc[’key’].value params._source[’key’]
  • 高版本的doc[’key’].value中的key不再支持IP类型

ID查找

在数据量非常巨大的情况下,通过ID查找文档最好使用官方的GET index/type/id,而非POST query:{term:{id:14}}

scroll:timevalue vs size

使用scroll时,timevalue应与size成正比,size越大越易超时,故timevalue应越大,不过timevalue最大到5m就差不多了

Scroll自动关闭

ES5、6以上,RestClient Scroll貌似查询到结尾会自动关闭

Scroll查询缓存

ES Scroll查询时,其实返回一批数据后,后面(分片数-1)批数据已经缓存好了,所以后面的(分片数-1)批获取也很快!故查询时,单次查询数量越多整个查询耗时越低,不过也要注意以下情况适当调整单次查询数量:

  • 网络较慢
  • ES负载较大
  • RestClilent方式(数据过大容易造成Timeout或者数据过大接收不了错误【高版本可设置HeapBufferResponseConsumerFactory来调大】)

加快Scroll速度:

  • search_type=scan
  • sort:”_doc” //不过如果size本身就是1的话就没必要了,一条记录不涉及到排序

ES常用字段操作

增加字段:

post  index/_mapping/type
{
    "type":{
        "properties":{
            "字段名":{
                "type":"string",
                "index":"not_analyzed"
            }
        }
    }
}

ES按条件更新字段:

post  index/type/_update_by_query
{
    "script":{
        "inline":"if(!ctx._source.containsKey(\"urllevel\")){ctx._source.attending=\"urllevel\"};ctx._source.urllevel=ctx._source.fullurl.split(\"/\").size();"
    },
    "query":{
        "match_all":{}
    }
}

ES Groovy截取字符串搜索:

get index/_search
{
    "query":{
        “bool”:{
            “must”:[
                {
                    "term":{
                        "field":"h-req-refer"
                    }
                },
                {
                    "script":{
                        "inline":"doc['h-req-refer'].value.substring(0,doc['h-req-refer'].value.firstIndexOf('/'))==doc['h-req-host']",
                        "lang":"groovy"
                    }
                }
            ]
        }
    }
}

ES聚合后,按照某字段内容总长度进行排序【自定义排序】

http://localhost:9200/index/type/_search   POST
{
    "size":0,
    "aggs":{
        "mydata":{
            "terms":{
                "field":"h-req-data",
                "order":{
                "max_length":"desc"
                },
            "size":3
            },
            "aggs":{
                "max_length":{
                    "max":{
                        "script":"doc['h-req-data'].value==null?0:doc['h-req-data'].value.split('[^a-zA-Z0-9=/%\\\\+]').sort(a,b->a.length()<==>b.length())[0].length()"
                    }
                }
            }
        }
    }
}

ES与多线程

处理ES时,并不是线程越多越好,应该让多线程做该做的事情:让多线程去处理逻辑判断,单线程或少量线程去请求IO(网络IO),因为IO总是瓶颈。 读程序:

while 单线程获取ES数据(可分页或scroll分批获取) 多线程逻辑处理ES数据,处理完成后put某个阻塞队列queue

写程序:

while 数据 = queue.take() 单线程将处理后的数据存入ES(增删改等)

ES重试

ES如果数据量巨大,经常发生超时现象(包括scroll时),可代码实现重试操作,就算是scroll超时,scroll_id传入ES,返回数据时超时,也不用担心,该scroll_id仍然可用,可重新使用该scroll_id进行查询。 **注意:**restclient可设置超时时间,而transport默认超时时间很长,但一旦超时,会一直卡死

各关键字查询效率

在布尔查询中,filter参数和must_not参数使用Filter Context,而mustshould使用Query Context,经常使用Filter Context,引擎会自动缓存数据,提高查询性能。

ES的更新

ES的更新分为全局更新和局部更新:

-XPOST 'http://192.168.80.200:9200/zhouls/emp/1/_update' -d
    '{"doc":{"name":"mack"}}'

-XPOST 'http://192.168.80.200:9200/zhouls/emp/1' -d
    '{"name":"mack"}'

后面的是全局更新,更新后其他字段值将不存在,只有name字段值

ES索引复制:

http://localhost:9200/_reindex   POST
{
      "source": {
        "index": "old_index"
    },
    "dest": {
        "index": "new_index",
        "op_type": "create"
    }
}

painless开启split功能

在painless中没有支持java string的split方法,但可以修改es配置开启正则的split语法

但在实际使用中发现性能损耗很大,一条执行一百毫秒左右的搜索语句,加上split后搜索时间升到七百毫秒左右,所以官方在未支持split方法时也指出本身string的split性能也不是很好,尽量避免使用

ES海量查询技巧

对于ES等大数据库,对于海量数据,查询需要花费时间常查的条件结果集可重入一个“缓存”索引,后续查询时,如果条件包含之前的条件,则可在缓存索引中查询(并带上剩余的条件)。

文章永久链接:https://tech.souyunku.com/19468

未经允许不得转载:搜云库技术团队 » ElasticSearch使用总结

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们