几个elasticsearch使用经验

栏目: 后端 · 发布时间: 6年前

内容简介:今天写几个近期ES项目的经验,供大家参考。强调一下,一定要用alias!这样当mapping有不兼容的升级时,可以实现线上0停机切换alias指向新库。

今天写几个近期ES项目的经验,供大家参考。

1,建库

强调一下,一定要用alias!

这样当mapping有不兼容的升级时,可以实现线上0停机切换alias指向新库。

使用alias后,一定不要随便delete alias!因为你一旦把alias删了,那么index请求就会自动创建与alias同名的mapping出来。正确做法应该是update alias先指向新库,然后再删除旧的index。

2,索引mapping

这块主要谈一下表结构规划的思路。

我的项目涉及到多种类型的文章,它们混合索引在一个mapping中。

对于各个类型通用的字段,可以直接放在mapping最外层。

2.1,object字段集合

对于相关性很高的一组字段,可以放在一个object字段里聚集起来,这样数据之间的关系就一目了然了。

比如A类型文章的独有属性,可以放在一个a_detail的object中;B类型文章的独有属性,可以放在一个b_detail的object中。

2.2,嵌套nested

如果需要保存object数组,则大胆的使用nested类型即可。

根据我的经验,它对query和aggregation的支持比较完善,没有遇到无法实现的功能。

2.3,禁用自动mapping

一定要给type(表)、object(对象)、nested(嵌套)三种类型配置dynamic属性:

  • 建议dynamic: false,当出现mapping未知字段时,不会更新mapping,但是index请求可以成功,未知字段会出现在_source中。
  • 超严格则dynamic: strict,对于未知字段,index请求将直接失败,抛出异常。

2.4,时间格式

用date字段,一定要指定format:

"format" => 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis',

这样就可以存储字符串或者毫秒的时间进去了。

但是注意,如果传的是字符串格式,那么ES会按UTC时区转成毫秒时间戳,然后建立倒排索引,这样索引中的时间戳实际上少了8个小时(中国时区的偏移量)。

在这种情况下,后续的查询一定要用字符串格式的时间,保持”将错就错”仍旧可以正常工作。

此时,_source中的内容仍旧是你索引时Json中的时间字符串,并不会受到时区的影响。

date最佳实践参考: https://blog.csdn.net/feifantiyan/article/details/54669583

3,查询

几乎所有的查询都走了bool的filter,在filter中可以嵌套子bool,多多利用filter有利于ES缓存结果。

3.1,索引时计算 or 查询时计算

因为有多种类型的文章,业务中有很多混合流,对不同类型文章的过滤规则各不相同,非常具体。

一开始曾试图将不同类型文章进行业务策略的梳理,即索引时计算出策略字段(相当于离线计算),这样查询时只需要直接过滤策略字段即可得到结果。但后来发现,混合流的业务规则非常灵活,后期产品策略随时会调整,所以决定基于业务属性查询时进行实时过滤。

在这种情况下,最好的建表方式就是把通用的字段提取出来,不通用的字段分离存储到不同的object字段中。

这样在实现混合流时,可以通过where (type=a and xxx=1 and yyy=2) or (type=b and mmm=1 and nnn=2)这种嵌套bool,实现对不同类型的各自过滤规则。

从ES语法角度来说,即外层bool should中嵌套多个子bool实现or关系,每个子bool中通过filter实现多个字段and关系,从而对不同类型文章做不同的过滤条件。

3.2,短语匹配

类似于 mysql 中的”%xxx%”这种模糊查询,实际上不是全文检索,而是短语匹配,即xxx需要完整的出现在目标字段中,而不是某个分词出现过。

所以,这种情况不要用match,用match_phrase。

3.3,painless打分脚本

混合流除了普通时间排序,大多需要策略排序。

策略 排序 是PM给规则,往往都需要写painless脚本实现打分的计算逻辑。

使用painless的时候比较坑的就是类型问题。

painless是动态语言,强类型,并不是弱类型,并且提供了def关键字,类似于c++中的auto,可以容纳任何类型的数据。

我们index索引json时,如果字段是Integer而你放进去的是”123″,那么ES会在构建倒排时做类型转换为integer,而在_source中仍旧是”123″。

此时,doc[“xxx”]取出来的一定是123,而params._source[“xxx”]则是”123″。

具体的关系我写在另外一篇博客中,大家特别注意即可: 《painless获取doc字段的方式》

3.4,自定义排序

在混合流中,业务策略要求A类文章按发布时间,B类文章按更新时间,综合排序。

即不同类型的文章,排序依据的字段不同。

这种情况用不到script field,只能用script sort实现,目前就我所知一旦使用script sort,就不能传多个sort条件了(多个条件是指:order by a asc, b desc),所以复杂排序比较鸡肋,可能还是得走相关性打分脚本解决。

顺便一提,script sort的type只支持数字和字符串,即你的排序脚本只能return这两种类型的值,供ES排序用。

4,聚合

聚合主要分清概念即可,有bucket agg与metric agg之分,可以无限嵌套下去。

比较新鲜的是nested bucket agg用来处理nested字段的分桶,filtered bucket agg用来在agg阶段做数据过滤(不同于query阶段的过滤)。

根据业务特点,尽量对聚合结果做一定时间的cache,因为这种聚合统计的计算量真的很大。

5,业务 -> 搜索 数据同步

这一块有2种选择:

  • 业务按照mapping拼好json,推给搜索服务,搜索服务直接入库
  • 业务将变化的数据ID通知给搜索,搜索拿着ID主动去业务拉取需要的数据,拼装出json

建议选择后者,原因有2个:

  • 最终一致性:业务仅仅发出通知,搜索主动拉取数据,这样搜索总是可以拿到最新的数据。
  • 控制权:毕竟是搜索服务直接与ES交互,因此搜索服务应该对数据具有绝对控制权,去各个业务系统获取所需数据拼装json。

即便采取了拉模式,ES仍旧有可能出现旧数据覆盖新数据的情况:2个并发拉取,谁后写到ES就算谁的。

这种问题可以用ES的版本控制解决,需要业务提供数据的版本号,不是太重要的业务数据可以忽略这个竞争问题。

6,搜索接口设计

其实给业务提供接口,一般是给某个页面提供具体服务。

感觉下来的话,还是很难在开始阶段就设计出一些通用的灵活接口,所以我并不建议在共性不明显的情况下做通用大接口的设计,先解决业务需求。

暂时能想到的就这些,希望对大家有所帮助。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Masterminds of Programming

Masterminds of Programming

Federico Biancuzzi、Chromatic / O'Reilly Media / 2009-03-27 / USD 39.99

Description Masterminds of Programming features exclusive interviews with the creators of several historic and highly influential programming languages. Think along with Adin D. Falkoff (APL), Jame......一起来看看 《Masterminds of Programming》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试