一口气看完 43 个关于 ElasticSearch 的使用建议( 四 )


正例:
第1步:通过stored方式,建script模版:POST _script/activity_discount_price{"script":{"lang":"pAInless","source":"doc.xxx.value * params.discount"}}第2步:调用script脚本模版:cal_activity_discountGET index/_search{"script_fields": {"discount_price": {"script": {"id": "activity_discount_price","params":{"discount": 0.8}}}}}反例:
//直接inline方式,请求中传入脚本:GET index/_search{"script_fields": {"activity_discount_price": {"script": {"source":"doc.xxx.value * 0.8"}}}}18. 避免使用 _all 字段 。_all 字段包含了所有的索引字段,如果没有获取原始文档数据的需求,可通过设置Includes、Excludes 属性来定义放入 _source 的字段 。_all 默认将写入的字段拼接成一个大的字符串,并对该字段进行分词,用于支持整个 Doc 的全文检索,“_all”字段在查询时占用更多的 CPU,同时占用更多的磁盘存储空间,默认为“false”,不建议开启该字段和使用 。
19. 建议用 Get 查询替换 Search 查询 。GET/MGET 直接根据文档 ID 从正排索引中获取内容 。Search 不指定_id,根据关键词从倒排索引中获取内容 。
20. 避免进行多索引查询 。反例:
GET /index1,index2,index3/_search{"query": {"match_all": {}}}21. 避免单次召回大量数据,建议使用 _source_includes 和 _source_excludes 参数来包含或排除字段 。大型文档尤其有用,部分字段检索可以节省网络开销 。
参考示例:
// 创建SearchSourceBuilder , 并设置查询条件SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.query(QueryBuilders.matchAllQuery());// 设置要包含的字段String[] includes = {"field1", "field2"};sourceBuilder.fetchSource(includes, Strings.EMPTY_ARRAY);// 设置要排除的字段String[] excludes = {"field3"};sourceBuilder.fetchSource(Strings.EMPTY_ARRAY, excludes);22. 避免使用 Wildcard 进行中缀模糊查询 。ES 官方文档并不推荐使用 Wildcard 来进行中缀模糊的查询,原因在于 ES 内部为了加速这种带有通配符查询,会将输入的字符串 Pattern 构建成一个 DFA (Deterministic Finite Automaton),而带有通配符的 Pattern 构造出来的 DFA 可能会很复杂 , 开销很大 。
建议使用 ES 官方在 7.9 推出的一种专门用来解决模糊查询慢的 Wildcard 字段类型 。与 Text 字段相比,它不会将文本看作是标点符号分割的单词集合;与 Keyword 字段比,它在中缀搜索场景下具有无与伦比的查询速度 , 且对输入没有大小限制 , 这是 Keyword 类型无法相比的 。
23. 避免使用 Scripting 。Painless 脚本语言语法相对简单,灵活度高,安全性高,性能高(相对于其他脚本,但是其性能比 DSL 要低) 。不适用于非复杂业务,一般 DSL 能解决大部分的问题,解决不了的用类似 Painless 等脚本语言 。主要性能影响如下:单次查询或更新耗时增加,脚本的执行时间相比于其他查询和更新操作可能会更长,因为在执行脚本之前需要对其进行词法分析、语法分析和代码编译等预处理工作 。
24. 避免使用脚本查询(Script Query)计算动态字段,建议在索引时计算并在文档中添加该字段 。例如,我们有一个包含大量用户信息的索引,我们需要查询以"1234"开头的所有用户 。运行一个脚本查询如"source":“doc[‘num’].value.startsWith(‘1234’)” 。这个查询非常耗费资源,索引时考虑添加“num_prefix”的keyword字段,然后查询"name_prefix":“1234” 。
三、写入相关25. 避免代码中或手工直接 Refresh 操作 。合理设置索引 Settings/Refresh_Interval 时间,通过系统完成 Refresh 动作 。
26. 避免单个文档过大 。鉴于默认 http.max_content_length 设置为 100MB,Elasticsearch 将拒绝索引任何大于该值的文档 。
27. 写入数据不指定 Doc_ID,让 ES 自动生成 。索引具有显式 ID 的文档时 ES 在写入过程中会多一步判断的过程,即检查具有相同ID 的文档是否已经存在于相同的分片中,随着索引增长而变得更加昂贵 。
28. 合理使用 Bulk API 批量写 。大数据量写入时可以使用 Bulk,但是请求响应的耗时会增加,即使连接断开,ES 集群内部也仍然在执行 。高速大批量数据写入时,可能造成集群短时间内响应缓慢甚至假死的的情况 。