社区日报 第469期 (2018-12-05)
http://t.cn/EyI2jxr
2.Lucene倒排索引简述 细说倒排索引构建
http://t.cn/EyI2eMN
3. 知乎如何基于开源Druid打造下一代数据平台
http://t.cn/E2Kmzj0
编辑:江水
归档:https://elasticsearch.cn/article/6173
订阅:https://tinyletter.com/elastic-daily
http://t.cn/EyI2jxr
2.Lucene倒排索引简述 细说倒排索引构建
http://t.cn/EyI2eMN
3. 知乎如何基于开源Druid打造下一代数据平台
http://t.cn/E2Kmzj0
编辑:江水
归档:https://elasticsearch.cn/article/6173
订阅:https://tinyletter.com/elastic-daily
收起阅读 »
Day 5 - Elasticsearch 存储设备全解析
day5 - es存储设备全解析
Elastic Search 作为一个分布式系统,它的最小单元(shard)实现基于 lucene , lucene是一个io密集cpu密集的系统。cpu密集可以通过使用更多核,更快的cpu以及优化算法来解决。而io密集部分需要搭配高性能的存储设备以及存储策略来解决。
传统的服务器硬盘分为SATA,SAS硬盘以及现在最高性能的SSD硬盘,其中SSD硬盘又分为 SATA SSD,PCI-E SSD ,M.2 SSD(性能依次提升)。
两者的区别在于 SATA 最高可以提供 7200转的。著名的HADOOP集群中,一半都会选择企业级SATA盘来降低存储成本。而SATA盘容易损坏以及恢复速度的问题,则交给10g高速网卡以及三副本策略来解决。
如果是了解数据库领域的同学就会知道,MySQL 之类的数据库严重推荐使用SSD来做存储。TiDB这种新时代的分布式数据库甚至在安装过程中会见存储是否是高性能设备,当时低速设备时,安装将失败。
如何查看io压力
iostat -x 1 100
可以根据 iowait , ioutil 等值来综合判断. 当iowait长期接近100%基本代表io系统出现瓶颈了。这时候可以用iotop
命令来诊断出具体是什么进程在消耗io资源。
如何测试硬盘性能
通过 fio 测试 顺序读/写,随机读/写性能。
顺序读 fio -name iops -rw=read -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 随机读 fio -name iops -rw=randread -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 顺序写 fio -name iops -rw=write -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 随机写 fio -name iops -rw=randwrite -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1
更具体的测试可以参考磁盘性能指标--IOPS、吞吐量及测试
RAID
RAID 0
将数据分布在N块盘中,速度最快,可以享受磁盘的并行读取和写入;安全性最低,一块盘损坏,将导致所有数据丢失。
RAID 1
将数据同时保存在N块盘中,写入速度最慢(需要同时写多块盘)。安全性最高。
RAID 10 ?
将RAID 1 和 RAID 0 结合起来,获得高安全性和高性能。最常用的RAID策略。同时也是TiDB,MySQL等数据库推荐的RAID策略。
RAID 5
RAID 5 最低三块盘,存储数据的异或编码,在一块盘损坏时,可以提供编码恢复出数据。
ElasticSearch 使用低速设备的 Tips
修改index.merge.scheduler.max_thread_count
参数为1;该参数影响lucene后台的合并线程数量,默认设置只适合SDD。多个合并线程可能导致io压力过大,触发 (linux 120s timeout)[https://cyberdak.github.io/es/2018/07/01/es-force-merge-cause-es-down].
存储策略
- 避免单机存储过多数据,如果单机故障,将导致集群需要大量数据,影响集群的吞吐量,特别是发生在高峰时候更会影响业务。千兆网卡每小时可以同步的数据为463gb,可以参考这个速度结合资深集群网卡以及存储来调节每个节点存储的数据量。
- 存储有条件使用RAID10,增加单节点性能以及避免单节点存储故障
RAID卡策略
根据服务器RAID卡的等级不同,高级的RAID卡可以使用 write-back 写策略,数据写入会直接写入到缓存中,随后刷新到硬盘上。当主机掉电时,由RAID卡带的电池来保证数据成功写入到硬盘中。write back的设置需要电池有电才能支持,而某些场景可以设置为force write-back
(即使电池没电了,也要写缓存),从而提高写入性能。
day5 - es存储设备全解析
Elastic Search 作为一个分布式系统,它的最小单元(shard)实现基于 lucene , lucene是一个io密集cpu密集的系统。cpu密集可以通过使用更多核,更快的cpu以及优化算法来解决。而io密集部分需要搭配高性能的存储设备以及存储策略来解决。
传统的服务器硬盘分为SATA,SAS硬盘以及现在最高性能的SSD硬盘,其中SSD硬盘又分为 SATA SSD,PCI-E SSD ,M.2 SSD(性能依次提升)。
两者的区别在于 SATA 最高可以提供 7200转的。著名的HADOOP集群中,一半都会选择企业级SATA盘来降低存储成本。而SATA盘容易损坏以及恢复速度的问题,则交给10g高速网卡以及三副本策略来解决。
如果是了解数据库领域的同学就会知道,MySQL 之类的数据库严重推荐使用SSD来做存储。TiDB这种新时代的分布式数据库甚至在安装过程中会见存储是否是高性能设备,当时低速设备时,安装将失败。
如何查看io压力
iostat -x 1 100
可以根据 iowait , ioutil 等值来综合判断. 当iowait长期接近100%基本代表io系统出现瓶颈了。这时候可以用iotop
命令来诊断出具体是什么进程在消耗io资源。
如何测试硬盘性能
通过 fio 测试 顺序读/写,随机读/写性能。
顺序读 fio -name iops -rw=read -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 随机读 fio -name iops -rw=randread -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 顺序写 fio -name iops -rw=write -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1 随机写 fio -name iops -rw=randwrite -bs=4k -runtime=60 -iodepth 32 -filename /dev/sda -ioengine libaio -direct=1
更具体的测试可以参考磁盘性能指标--IOPS、吞吐量及测试
RAID
RAID 0
将数据分布在N块盘中,速度最快,可以享受磁盘的并行读取和写入;安全性最低,一块盘损坏,将导致所有数据丢失。
RAID 1
将数据同时保存在N块盘中,写入速度最慢(需要同时写多块盘)。安全性最高。
RAID 10 ?
将RAID 1 和 RAID 0 结合起来,获得高安全性和高性能。最常用的RAID策略。同时也是TiDB,MySQL等数据库推荐的RAID策略。
RAID 5
RAID 5 最低三块盘,存储数据的异或编码,在一块盘损坏时,可以提供编码恢复出数据。
ElasticSearch 使用低速设备的 Tips
修改index.merge.scheduler.max_thread_count
参数为1;该参数影响lucene后台的合并线程数量,默认设置只适合SDD。多个合并线程可能导致io压力过大,触发 (linux 120s timeout)[https://cyberdak.github.io/es/2018/07/01/es-force-merge-cause-es-down].
存储策略
- 避免单机存储过多数据,如果单机故障,将导致集群需要大量数据,影响集群的吞吐量,特别是发生在高峰时候更会影响业务。千兆网卡每小时可以同步的数据为463gb,可以参考这个速度结合资深集群网卡以及存储来调节每个节点存储的数据量。
- 存储有条件使用RAID10,增加单节点性能以及避免单节点存储故障
RAID卡策略
根据服务器RAID卡的等级不同,高级的RAID卡可以使用 write-back 写策略,数据写入会直接写入到缓存中,随后刷新到硬盘上。当主机掉电时,由RAID卡带的电池来保证数据成功写入到硬盘中。write back的设置需要电池有电才能支持,而某些场景可以设置为force write-back
(即使电池没电了,也要写缓存),从而提高写入性能。
Day 4 - PB级规模数据的Elasticsearch分库分表实践
从2018年7月在开始在某阿里云数据中心部署Elasticsearch软件,到2018年12月共创建了15个集群,服务于客户的文档检索、交通视频检索、地理信息检索、日志安全审计等业务。其中数据规模最大的一个业务,共有800张表,7万亿条数据,每天新增500亿条记录,数据要求存储半年,单条记录大小1KB左右,存储规模约10PB,需要支持1000并发查询。
一、数据存储空间规划。
数据中心能用于搭建Elasticsearch集群的SSD盘共700TB,SATA盘共50PB。根据业务类型、时间范围划分热数据和冷数据,一部分重要数据存储在SSD盘的热数据集群,其它数据存储在SATA盘的冷数据集群。热数据集群主要存储各类实体信息,包括人员、物品、事件、地址、组织数据,以及最新轨迹数据。冷数据集群主要存储历史轨迹信息。热数据和冷数据按照业务拆分多个小集群,每个集群规模保持在50个节点左右,单个集群最大不超过200个节点。利用阿里云平台弹性伸缩的能力,每个Elasticsearch集群可以先从小规模创建,根据资源使用情况来弹性扩展节点规模。
Elasticsearch集群节点配置
二、索引设计。
1.索引别名(alias)。每类数据根据数据源表名建立索引(index),索引中只包含一个类型(type)。配置索引别名(alias),业务上根据别名写入、查询数据,索引重建等数据维护操作可以通过别名切换对业务透明。
2.按时间分表。轨迹类数据按时间(日/月)拆分,每个索引存储数据量保持在1TB(10亿)左右,索引名带上日期/月份后缀,拆分后的索引配置别名区分冷热数据。配置索引模板,指定索引分片数和副本数、字段类型、分词器。配置Linux crontab定时任务,通过shell脚本创建索引。
3.分片(shard)设置。索引按照单个分片10-40GB数据大小设计分片数,数据量少于10GB(1000万)的索引设置1个分片即可,数据量大于1TB(10亿)的索引设置分片数为集群节点数整数倍(例如50个节点的集群配置50个分片)。
4.副本(replica)设置。数据首次批量导入时索引副本数设置为0,快速写入数据。生产环境索引副本数设置为1,避免集群节点故障数据丢失。
三、索引mapping设计。
1.精心设计索引字段类型。在开发环境配置Elasticsearch允许自动创建索引,从数据源每张表取1000条记录批量写入Elasticsearch,自动创建索引mapping,然后再根据业务需要修改mapping配置合适的字段类型,指定字段索引分词器、是否存储、是否索引、是否合并至全文检索字段。 对于数据量大的表尤其要精心设计字段类型,尽量减少索引存储空间占用。在生产环境中建议配置不允许自动创建索引。
2.配置全文检索字段。如果业务需要全文检索,可以配置开启全文字段,同时需要占用更多存储空间;如果业务上只是按字段查询,可以配置禁用全文字段,减少存储空间。Elasticsearch5.X及之前的版本默认启用_all字段,合并所有字段的值。Elasticsearch6.X及之后的版本默认禁用_all字段,可以通过copy_to将多个字段值合并成一个全文字段。对于数据查全率要求高的业务场景,建议对全文字段配置cjk分词器(Elasticsearch和Lucene中自带,对中日韩文进行二元分词的分词器)。
3.通用字段统一命名。各个索引中的姓名、证件号码、时间(开始时间、结束时间)、地点(始发地、目的地)等常用字段统一命名。用户指定证件号、时间范围等精确字段查询条件时,可以使用统一的查询条件并行查询多个索引。
四、分词设置。
1.选择合适的分词器。Elasticsearch中内置了很多分词器:standard、cjk、nGram等,也可以安装ik、pinyin等开源分词器, 可以根据业务场景选择合适的分词器。 常用分词器: standard:Elasticsearch默认分词,英文按空格切分,中文按单个汉字切分。 cjk:根据二元索引(两个相邻的字作为一个词条)对中日韩文分词,可以保证查全率。 NGram:可以将英文按照字母切分,结合Elasticsearch的短语搜索(match_phrase)使用。 ik:比较热门的中文分词,能按照中文语义切分,可以自定义词典。 pinyin:可以让用户输入拼音,就能查找到相关的关键词。 对于查全率要求较高的场景,建议使用cjk分词,同时能支持比较快的响应速度。对于查准率要求较高的场景,建议使用ik分词。
CJK分词和IK分词对比(测试环境:Elasticsearch5.5.3,8335万条人员档案信息,10节点集群,单节点16核CPU、64G内存、2T SSD盘,1个线程批量写入,1个并发查询)
测试分词效果: curl -XPOST "http://localhost:9200/_analyze" -H 'Content-Type: application/json' -d' { "analyzer": "ik_max_word", "text": "南京市长江大桥" }'
2.NGram分词。对于像车牌号之类数字和字母连在一起的字符,默认会被切成一个完整词条,但是业务上又需要支持前缀、后缀模糊匹配,可以根据业务需求进行分词。车牌号建议增加一个分词字段,配置NGram分词器,切分1元至7元的组合。身份证号码建议增加分词字段,根据业务需要切分18位完整词条、前2位(省)、前4位(省市)、前6位(省市区县)、后4位、出生年月日、出生年份、出生年月、出生月日等组合。
3.单字分词。对于像姓名类字段,业务上需要支持完整匹配,又需要支持单字查询。可以配置1个keyword字段(不分词);1个text字段(分词),分词器选择Elasticsearch默认分词器standard,按单个汉字切分。
五、数据写入策略。
1.批量离线数据导入。各类业务数据源主要在数据仓库MaxCompute(原ODPS),为了把表数据从MaxCompute表导入到ElasticSearch集群中, 我们基于MaxCompute MapReduce开发了MaxCompute到ElasticSearch的数据导出作业,通过简单的配置就可以把数据导入到ElasticSearch中。 数据源在关系数据库RDS或者NoSQL的数据,可以通过配置DataWorks(dataX企业版)导入Elasticsearch集群。
2.实时数据导入。实时数据源主要是流式数据服务DataHub, 配置DataHub任务即可同步至Elasticsearch集群。也可以自己开发程序调用DataHub的SDK获取实时数据,经过业务处理后,调用ES Rest Client SDK批量写入Elasticsearch。
3.冷热数据自动迁移。轨迹类实时数据默认先写入热数据集群(SSD盘Elasticsearch集群),对于热数据集群过期的索引(例如1个月前的索引)需要迁移到冷数据集群(SATA盘Elasticsearch)。为了实现数据跨集群迁移,我们开发了snapshot插件将索引备份到对象存储服务OSS或分布式文件系统盘古。配置定时任务,将热数据集群索引备份后,从冷数据集群恢复,然后再删除热集群中的过期索引,保持热数据集群只存储较小规模数据。冷数据集群的索引如果超过半年,则关闭索引,减少JVM堆内存占用。
4.配置索引主键字段。为了保证Elasticsearch集群和数据源记录的一致性,建议所有索引配置主键字段,而不是让Elasticsearch自动生成主键。配置数据业务主键字段作为Elasticsearch主键字段。如果没有主键字段,则将原始数据能确定记录惟一性的几个字段合并为主键,或者将所有字段值合并起来计算MD5值作为主键。
5.配置写入路由。如果业务上需要经常根据某个字段查询,例如用户ID、车牌号等的字段,写入时可以指定路由字段。
6.写入参数调优。调整数据写入任务参数,避免写入操作占用过多磁盘IO和CPU。使用批量请求,配置合理的写入线程数,调大索引刷新时间间隔refresh interval,调整事务日志translog同步策略。
六、数据查询策略。
1.冷热库异步查询。用户输入关键词查询时,优先从热数据集群查询,有结果立即返回,并估算命中记录条数。热数据集群命中结果集不足时,再查询冷数据集群。
2.跨集群搜索。业务上需要多个Elasticsearch集群一起参与检索时,可以通过Cross Cluster Search同时对多个集群发起检索请求合并检索结果。单独创建一个5节点的Cross Cluster,设置远程集群节点信息,用于跨集群搜索,不存储业务数据。
3.快速返回和超时设置。查询请求中设置参数teminate_after指定每个分片(shard)最多匹配N条记录后返回(例如10000),设置查询超时时间timeout(例如10s),避免查询一些宽泛的条件时耗费过多系统资源。
4.查询语法解析。解析用户查询条件,识别用户的查询类型,例如用户输入车牌号、证件号、年龄段等条件时,查询条件改写为字段精确匹配,无法识别的查询条件默认从全文字段匹配。
5.查询条件调优。查询结果不需要相关度排序时使用过滤器(filter),尽量使用路由(routing),设置较少的查询读取记录条数和字段,避免前缀模糊匹配,设置search_after规避深度翻页性能问题。
七、数据写入、查询性能测试。
SSD盘集群写入性能测试(测试环境:Elasticsearch6.3.2集群,单节点16核CPU、64G内存、2T SSD盘,写入10亿条记录,单条记录1KB,副本数为0,1台写入服务器):
SSD盘集群查询性能测试
SATA盘集群写入性能测试(测试环境:Elasticsearch5.5.3集群,单节点56核CPU、128G内存、12块 6T SATA盘,分别写入1亿、3亿、5亿、30亿、300亿条记录,单条记录1KB,0副本,50台写入服务器):
SATA盘集群查询性能测试
参考文档:
- 阿里云Elasticsearch帮助文档 https://help.aliyun.com/product/57736.html
- Elasticsearch参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
- 《Elasticsearch: 权威指南》 https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
- 《深入理解Elasticsearch》https://detail.tmall.com/item.htm?id=551001166567
- 《死磕Elasticsearch方法论》https://blog.csdn.net/laoyang360/article/details/79293493
- Elasticsearch索引别名和零停机 https://www.elastic.co/guide/cn/elasticsearch/guide/current/index-aliases.html
- Elasticsearch自动按天创建索引脚本 https://blog.csdn.net/reblue520/article/details/80553317
- Elasticsearch NGram分词器 https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html
- Elasticsearch开源权限管理认证插件Search Guard https://github.com/floragunncom/search-guard
- Elasticsearch开源可视化管理插件cerebro https://github.com/lmenezes/cerebro
- Elasticsearch开源SQL插件 https://github.com/NLPchina/elasticsearch-sql
- Elasticsearch快照及恢复 https://help.aliyun.com/document_detail/65675.html
Elasticsearch技术交流钉钉群
从2018年7月在开始在某阿里云数据中心部署Elasticsearch软件,到2018年12月共创建了15个集群,服务于客户的文档检索、交通视频检索、地理信息检索、日志安全审计等业务。其中数据规模最大的一个业务,共有800张表,7万亿条数据,每天新增500亿条记录,数据要求存储半年,单条记录大小1KB左右,存储规模约10PB,需要支持1000并发查询。
一、数据存储空间规划。
数据中心能用于搭建Elasticsearch集群的SSD盘共700TB,SATA盘共50PB。根据业务类型、时间范围划分热数据和冷数据,一部分重要数据存储在SSD盘的热数据集群,其它数据存储在SATA盘的冷数据集群。热数据集群主要存储各类实体信息,包括人员、物品、事件、地址、组织数据,以及最新轨迹数据。冷数据集群主要存储历史轨迹信息。热数据和冷数据按照业务拆分多个小集群,每个集群规模保持在50个节点左右,单个集群最大不超过200个节点。利用阿里云平台弹性伸缩的能力,每个Elasticsearch集群可以先从小规模创建,根据资源使用情况来弹性扩展节点规模。
Elasticsearch集群节点配置
二、索引设计。
1.索引别名(alias)。每类数据根据数据源表名建立索引(index),索引中只包含一个类型(type)。配置索引别名(alias),业务上根据别名写入、查询数据,索引重建等数据维护操作可以通过别名切换对业务透明。
2.按时间分表。轨迹类数据按时间(日/月)拆分,每个索引存储数据量保持在1TB(10亿)左右,索引名带上日期/月份后缀,拆分后的索引配置别名区分冷热数据。配置索引模板,指定索引分片数和副本数、字段类型、分词器。配置Linux crontab定时任务,通过shell脚本创建索引。
3.分片(shard)设置。索引按照单个分片10-40GB数据大小设计分片数,数据量少于10GB(1000万)的索引设置1个分片即可,数据量大于1TB(10亿)的索引设置分片数为集群节点数整数倍(例如50个节点的集群配置50个分片)。
4.副本(replica)设置。数据首次批量导入时索引副本数设置为0,快速写入数据。生产环境索引副本数设置为1,避免集群节点故障数据丢失。
三、索引mapping设计。
1.精心设计索引字段类型。在开发环境配置Elasticsearch允许自动创建索引,从数据源每张表取1000条记录批量写入Elasticsearch,自动创建索引mapping,然后再根据业务需要修改mapping配置合适的字段类型,指定字段索引分词器、是否存储、是否索引、是否合并至全文检索字段。 对于数据量大的表尤其要精心设计字段类型,尽量减少索引存储空间占用。在生产环境中建议配置不允许自动创建索引。
2.配置全文检索字段。如果业务需要全文检索,可以配置开启全文字段,同时需要占用更多存储空间;如果业务上只是按字段查询,可以配置禁用全文字段,减少存储空间。Elasticsearch5.X及之前的版本默认启用_all字段,合并所有字段的值。Elasticsearch6.X及之后的版本默认禁用_all字段,可以通过copy_to将多个字段值合并成一个全文字段。对于数据查全率要求高的业务场景,建议对全文字段配置cjk分词器(Elasticsearch和Lucene中自带,对中日韩文进行二元分词的分词器)。
3.通用字段统一命名。各个索引中的姓名、证件号码、时间(开始时间、结束时间)、地点(始发地、目的地)等常用字段统一命名。用户指定证件号、时间范围等精确字段查询条件时,可以使用统一的查询条件并行查询多个索引。
四、分词设置。
1.选择合适的分词器。Elasticsearch中内置了很多分词器:standard、cjk、nGram等,也可以安装ik、pinyin等开源分词器, 可以根据业务场景选择合适的分词器。 常用分词器: standard:Elasticsearch默认分词,英文按空格切分,中文按单个汉字切分。 cjk:根据二元索引(两个相邻的字作为一个词条)对中日韩文分词,可以保证查全率。 NGram:可以将英文按照字母切分,结合Elasticsearch的短语搜索(match_phrase)使用。 ik:比较热门的中文分词,能按照中文语义切分,可以自定义词典。 pinyin:可以让用户输入拼音,就能查找到相关的关键词。 对于查全率要求较高的场景,建议使用cjk分词,同时能支持比较快的响应速度。对于查准率要求较高的场景,建议使用ik分词。
CJK分词和IK分词对比(测试环境:Elasticsearch5.5.3,8335万条人员档案信息,10节点集群,单节点16核CPU、64G内存、2T SSD盘,1个线程批量写入,1个并发查询)
测试分词效果: curl -XPOST "http://localhost:9200/_analyze" -H 'Content-Type: application/json' -d' { "analyzer": "ik_max_word", "text": "南京市长江大桥" }'
2.NGram分词。对于像车牌号之类数字和字母连在一起的字符,默认会被切成一个完整词条,但是业务上又需要支持前缀、后缀模糊匹配,可以根据业务需求进行分词。车牌号建议增加一个分词字段,配置NGram分词器,切分1元至7元的组合。身份证号码建议增加分词字段,根据业务需要切分18位完整词条、前2位(省)、前4位(省市)、前6位(省市区县)、后4位、出生年月日、出生年份、出生年月、出生月日等组合。
3.单字分词。对于像姓名类字段,业务上需要支持完整匹配,又需要支持单字查询。可以配置1个keyword字段(不分词);1个text字段(分词),分词器选择Elasticsearch默认分词器standard,按单个汉字切分。
五、数据写入策略。
1.批量离线数据导入。各类业务数据源主要在数据仓库MaxCompute(原ODPS),为了把表数据从MaxCompute表导入到ElasticSearch集群中, 我们基于MaxCompute MapReduce开发了MaxCompute到ElasticSearch的数据导出作业,通过简单的配置就可以把数据导入到ElasticSearch中。 数据源在关系数据库RDS或者NoSQL的数据,可以通过配置DataWorks(dataX企业版)导入Elasticsearch集群。
2.实时数据导入。实时数据源主要是流式数据服务DataHub, 配置DataHub任务即可同步至Elasticsearch集群。也可以自己开发程序调用DataHub的SDK获取实时数据,经过业务处理后,调用ES Rest Client SDK批量写入Elasticsearch。
3.冷热数据自动迁移。轨迹类实时数据默认先写入热数据集群(SSD盘Elasticsearch集群),对于热数据集群过期的索引(例如1个月前的索引)需要迁移到冷数据集群(SATA盘Elasticsearch)。为了实现数据跨集群迁移,我们开发了snapshot插件将索引备份到对象存储服务OSS或分布式文件系统盘古。配置定时任务,将热数据集群索引备份后,从冷数据集群恢复,然后再删除热集群中的过期索引,保持热数据集群只存储较小规模数据。冷数据集群的索引如果超过半年,则关闭索引,减少JVM堆内存占用。
4.配置索引主键字段。为了保证Elasticsearch集群和数据源记录的一致性,建议所有索引配置主键字段,而不是让Elasticsearch自动生成主键。配置数据业务主键字段作为Elasticsearch主键字段。如果没有主键字段,则将原始数据能确定记录惟一性的几个字段合并为主键,或者将所有字段值合并起来计算MD5值作为主键。
5.配置写入路由。如果业务上需要经常根据某个字段查询,例如用户ID、车牌号等的字段,写入时可以指定路由字段。
6.写入参数调优。调整数据写入任务参数,避免写入操作占用过多磁盘IO和CPU。使用批量请求,配置合理的写入线程数,调大索引刷新时间间隔refresh interval,调整事务日志translog同步策略。
六、数据查询策略。
1.冷热库异步查询。用户输入关键词查询时,优先从热数据集群查询,有结果立即返回,并估算命中记录条数。热数据集群命中结果集不足时,再查询冷数据集群。
2.跨集群搜索。业务上需要多个Elasticsearch集群一起参与检索时,可以通过Cross Cluster Search同时对多个集群发起检索请求合并检索结果。单独创建一个5节点的Cross Cluster,设置远程集群节点信息,用于跨集群搜索,不存储业务数据。
3.快速返回和超时设置。查询请求中设置参数teminate_after指定每个分片(shard)最多匹配N条记录后返回(例如10000),设置查询超时时间timeout(例如10s),避免查询一些宽泛的条件时耗费过多系统资源。
4.查询语法解析。解析用户查询条件,识别用户的查询类型,例如用户输入车牌号、证件号、年龄段等条件时,查询条件改写为字段精确匹配,无法识别的查询条件默认从全文字段匹配。
5.查询条件调优。查询结果不需要相关度排序时使用过滤器(filter),尽量使用路由(routing),设置较少的查询读取记录条数和字段,避免前缀模糊匹配,设置search_after规避深度翻页性能问题。
七、数据写入、查询性能测试。
SSD盘集群写入性能测试(测试环境:Elasticsearch6.3.2集群,单节点16核CPU、64G内存、2T SSD盘,写入10亿条记录,单条记录1KB,副本数为0,1台写入服务器):
SSD盘集群查询性能测试
SATA盘集群写入性能测试(测试环境:Elasticsearch5.5.3集群,单节点56核CPU、128G内存、12块 6T SATA盘,分别写入1亿、3亿、5亿、30亿、300亿条记录,单条记录1KB,0副本,50台写入服务器):
SATA盘集群查询性能测试
参考文档:
- 阿里云Elasticsearch帮助文档 https://help.aliyun.com/product/57736.html
- Elasticsearch参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
- 《Elasticsearch: 权威指南》 https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
- 《深入理解Elasticsearch》https://detail.tmall.com/item.htm?id=551001166567
- 《死磕Elasticsearch方法论》https://blog.csdn.net/laoyang360/article/details/79293493
- Elasticsearch索引别名和零停机 https://www.elastic.co/guide/cn/elasticsearch/guide/current/index-aliases.html
- Elasticsearch自动按天创建索引脚本 https://blog.csdn.net/reblue520/article/details/80553317
- Elasticsearch NGram分词器 https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html
- Elasticsearch开源权限管理认证插件Search Guard https://github.com/floragunncom/search-guard
- Elasticsearch开源可视化管理插件cerebro https://github.com/lmenezes/cerebro
- Elasticsearch开源SQL插件 https://github.com/NLPchina/elasticsearch-sql
- Elasticsearch快照及恢复 https://help.aliyun.com/document_detail/65675.html
Elasticsearch技术交流钉钉群
收起阅读 »社区日报 第468期 (2018-12-04)
http://t.cn/EyyWjcy
2、详细介绍如何在kubernetes上构建EFK。
http://t.cn/EyyTOef
3、Laravel 使用 scout 集成 elasticsearch 做全文搜索。
http://t.cn/EyyWr5o
编辑:叮咚光军
归档:https://elasticsearch.cn/publish/article/6170
订阅:https://tinyletter.com/elastic-daily
http://t.cn/EyyWjcy
2、详细介绍如何在kubernetes上构建EFK。
http://t.cn/EyyTOef
3、Laravel 使用 scout 集成 elasticsearch 做全文搜索。
http://t.cn/EyyWr5o
编辑:叮咚光军
归档:https://elasticsearch.cn/publish/article/6170
订阅:https://tinyletter.com/elastic-daily 收起阅读 »
社区日报 第467期 (2018-12-03)
http://t.cn/EyhRQRJ
2.Amazon Elasticsearch Service 中的韩语分析程序支持
http://t.cn/EyhmEHc
3. Elasticsearch在华泰证券内部的应用实践
http://t.cn/EyhuaFC
编辑:cyberdak
归档:https://elasticsearch.cn/article/6169
订阅:https://tinyletter.com/elastic-daily
http://t.cn/EyhRQRJ
2.Amazon Elasticsearch Service 中的韩语分析程序支持
http://t.cn/EyhmEHc
3. Elasticsearch在华泰证券内部的应用实践
http://t.cn/EyhuaFC
编辑:cyberdak
归档:https://elasticsearch.cn/article/6169
订阅:https://tinyletter.com/elastic-daily 收起阅读 »
Day 3 - kibana二次开发tips
介绍
大家好,我是vvv,这个名字和王者荣耀AG超玩会中的vv没有一毛钱关系,随意取的一个的名字,后来发现貌似不能改了。做过一些数据产品,正是这段时间里开始接触elasticstack,对kibana做过一些二次开发。今天主要想写一些开发过程中的一些tips,希望可以给大家带来一些帮助。
技术栈分析
既然我们的主题是kibana,我们先来看下kibana的主要技术栈。很早开始kibana就开始基于nodejs (hapi框架) + angular(1.x)来进行开发,后来引入了react。kibana本身的代码也经过了多次重构剥离。现在的kibana的代码结构更加清晰
前提
elasticstack发展迅速,现在已经是6.5版本了。我们今天要介绍的是6.x系列的版本,6.x各个版本会有一些细微差异,但大致一样
tips
官方提供kibana下载版本主要是编译后的release版本。如果要基于kibana做二次开发,我们需要去https://github.com/elastic/kibana 上面下载对应的分支。官方有相应的文档去说明如何安装开发环境。我这里有一些tips:
设置国内yarn源
yarn config --global set 'registry https://registry.npm.taobao.org'
一些耗时需要编译的包可以全局安装
yarn global add node-sass
多环境nodejs版本
不同kibana版本对nodejs版本要求也不一样,为了减少坑我们通常和官方要求的保持一致,如果你的电脑上需要运行多套不同版本的nodejs,那么你可能需要zsh + nvs, 会根据根目录的.node-version版本自动切换当前使用的node版本
IDE推荐
推荐使用vscode,轻量免费,支持很多插件。可以安装个prettier插件,帮助对代码做更好的格式化
debug
如果你用的不是上面我推荐的vscode的话,请忽略这一条。对于使用vscode的同学,首先在vsocde的设置里面开启:
"autoAttach": "on"
然后在vsocode里面打开一个终端,输入:
node --inspect-brk scripts/kibana.js --dev --oss --no-base-path
这个时候vscode就会在启动kibana dev模式的同时attach一个进程进去用于断点调试,对于调试node层非常方便。也能帮助你更好的阅读kibana源码
本地es
我们知道kibana是长在es之上,想要运行kibana怎么少得了es。kibana又一些命令命令可以快速的启动一个es环境:
下载并启动一个当前kibana需要的es版本
yarn es snapshot
灌入一些测试数据(如果需要定制灌入的数据可以看下这个脚本的帮助内容,加-h参数即可)
node scripts/makelogs
编译
kibana代码在release之前是要进行编译的。kibana提供了方便的命令行进行编译,甚至跨平台的交叉编译(生成不同平台的kibana release版本)。但是呢,有几个问题:
- kibana在编译的时候需要去aws上下载一些安装包,会导致正常情况下国内访问十分缓慢。(编译命令提供了几个参数可以关掉下载一些如nodejs等,但是还是很慢)
- build十分消耗cpu/gpu (mac的iterm2启动会做gpu优化)
解决办法:
- 如果你能解决网络问题,而且有性能不错的编译机器。这都不是问题
- 如果你对kibana的代码更改都是无侵入的(比如只是写了一些插件扩展),那么你可以去官方下载他们的snapshot版本
- 当然,如果你用的kibana版本就是release版本并且你的扩展都是插件,那么你直接用官方的release版本就好了
库的选型
-
server端: nodejs具有十分丰富的生态,你可以找到很多nodejs相关的库。kibana本身的后端web框架是基于node的hapi的。hapi是一个沃尔玛团队维护的企业级框架,其本身也有很多扩展。当你需要对web框架做一些扩展的时候,可以优先想到去hapi官方看下
- ui端: kibana有一套漂亮的ui,其本身也是单独剥离成了一个库,方便引入使用。当然你也可以引入一些其他的前端库来满足你的具体业务需求。推荐尽量使用原生的eui和kibana源码里面的一些封装。这样让你的引入更少,更容易维护。
国际化
国际化是kibana很早就开始立的一个项。这块的进度也是越来越快。新版的kibana里面用@kbn/i18n这个package来统一javascript,html, nodejs做国际化的事情(具体大家可以看下这个package的readme)。国际化这块有一些建议:
- 扩展插件的时候养成国际化的习惯
- 默认的语系不建议再次设置成一个json文件。因为最新的@kbn/i18n会提供一个默认的文本,用于默认情况下展示。所以我们是没必要重复去维护一个默认的语言翻译json
- 假设你的默认语言是英文(和kibana一致),只有当你想要替换kibana默认翻译的时候,才去覆写en.json
- 当你对原生kibana有国际化这种需求的时候,建议独立出一个i18n翻译的插件去维护各个语言翻译相关的东西
- 目前kibana的国际化还未100%,如果你想知道目前哪些文本内容是支持国际化的。可以尝试如下脚本:
node scripts/extract_default_translations \
--path src/core_plugins/kibana \
--output /tmp
- 各个插件的之间的翻译文件独立,即使是相同的翻译内容。插件文本内容养成预留国际化的习惯
总结
上面列举了一些我平时的一些经验。时间篇幅有限,未能一一列举。希望可以帮到大家吧。也希望可以和大家多多交流
介绍
大家好,我是vvv,这个名字和王者荣耀AG超玩会中的vv没有一毛钱关系,随意取的一个的名字,后来发现貌似不能改了。做过一些数据产品,正是这段时间里开始接触elasticstack,对kibana做过一些二次开发。今天主要想写一些开发过程中的一些tips,希望可以给大家带来一些帮助。
技术栈分析
既然我们的主题是kibana,我们先来看下kibana的主要技术栈。很早开始kibana就开始基于nodejs (hapi框架) + angular(1.x)来进行开发,后来引入了react。kibana本身的代码也经过了多次重构剥离。现在的kibana的代码结构更加清晰
前提
elasticstack发展迅速,现在已经是6.5版本了。我们今天要介绍的是6.x系列的版本,6.x各个版本会有一些细微差异,但大致一样
tips
官方提供kibana下载版本主要是编译后的release版本。如果要基于kibana做二次开发,我们需要去https://github.com/elastic/kibana 上面下载对应的分支。官方有相应的文档去说明如何安装开发环境。我这里有一些tips:
设置国内yarn源
yarn config --global set 'registry https://registry.npm.taobao.org'
一些耗时需要编译的包可以全局安装
yarn global add node-sass
多环境nodejs版本
不同kibana版本对nodejs版本要求也不一样,为了减少坑我们通常和官方要求的保持一致,如果你的电脑上需要运行多套不同版本的nodejs,那么你可能需要zsh + nvs, 会根据根目录的.node-version版本自动切换当前使用的node版本
IDE推荐
推荐使用vscode,轻量免费,支持很多插件。可以安装个prettier插件,帮助对代码做更好的格式化
debug
如果你用的不是上面我推荐的vscode的话,请忽略这一条。对于使用vscode的同学,首先在vsocde的设置里面开启:
"autoAttach": "on"
然后在vsocode里面打开一个终端,输入:
node --inspect-brk scripts/kibana.js --dev --oss --no-base-path
这个时候vscode就会在启动kibana dev模式的同时attach一个进程进去用于断点调试,对于调试node层非常方便。也能帮助你更好的阅读kibana源码
本地es
我们知道kibana是长在es之上,想要运行kibana怎么少得了es。kibana又一些命令命令可以快速的启动一个es环境:
下载并启动一个当前kibana需要的es版本
yarn es snapshot
灌入一些测试数据(如果需要定制灌入的数据可以看下这个脚本的帮助内容,加-h参数即可)
node scripts/makelogs
编译
kibana代码在release之前是要进行编译的。kibana提供了方便的命令行进行编译,甚至跨平台的交叉编译(生成不同平台的kibana release版本)。但是呢,有几个问题:
- kibana在编译的时候需要去aws上下载一些安装包,会导致正常情况下国内访问十分缓慢。(编译命令提供了几个参数可以关掉下载一些如nodejs等,但是还是很慢)
- build十分消耗cpu/gpu (mac的iterm2启动会做gpu优化)
解决办法:
- 如果你能解决网络问题,而且有性能不错的编译机器。这都不是问题
- 如果你对kibana的代码更改都是无侵入的(比如只是写了一些插件扩展),那么你可以去官方下载他们的snapshot版本
- 当然,如果你用的kibana版本就是release版本并且你的扩展都是插件,那么你直接用官方的release版本就好了
库的选型
-
server端: nodejs具有十分丰富的生态,你可以找到很多nodejs相关的库。kibana本身的后端web框架是基于node的hapi的。hapi是一个沃尔玛团队维护的企业级框架,其本身也有很多扩展。当你需要对web框架做一些扩展的时候,可以优先想到去hapi官方看下
- ui端: kibana有一套漂亮的ui,其本身也是单独剥离成了一个库,方便引入使用。当然你也可以引入一些其他的前端库来满足你的具体业务需求。推荐尽量使用原生的eui和kibana源码里面的一些封装。这样让你的引入更少,更容易维护。
国际化
国际化是kibana很早就开始立的一个项。这块的进度也是越来越快。新版的kibana里面用@kbn/i18n这个package来统一javascript,html, nodejs做国际化的事情(具体大家可以看下这个package的readme)。国际化这块有一些建议:
- 扩展插件的时候养成国际化的习惯
- 默认的语系不建议再次设置成一个json文件。因为最新的@kbn/i18n会提供一个默认的文本,用于默认情况下展示。所以我们是没必要重复去维护一个默认的语言翻译json
- 假设你的默认语言是英文(和kibana一致),只有当你想要替换kibana默认翻译的时候,才去覆写en.json
- 当你对原生kibana有国际化这种需求的时候,建议独立出一个i18n翻译的插件去维护各个语言翻译相关的东西
- 目前kibana的国际化还未100%,如果你想知道目前哪些文本内容是支持国际化的。可以尝试如下脚本:
node scripts/extract_default_translations \
--path src/core_plugins/kibana \
--output /tmp
- 各个插件的之间的翻译文件独立,即使是相同的翻译内容。插件文本内容养成预留国际化的习惯
总结
上面列举了一些我平时的一些经验。时间篇幅有限,未能一一列举。希望可以帮到大家吧。也希望可以和大家多多交流
收起阅读 »【 报名开启】2018 Elastic & 袋鼠云 & 阿里云技术沙龙(杭州)
本次袋鼠云联合阿里云、Elastic 中文社区,共同邀请滴滴、有赞等行业技术专家一同分享和探讨各自领域Elastic的实践。
本次活动时间为12月15日 周六,人数限制100人,大家抓紧报名哈,报名链接https://meetup.elasticsearch.c ... .html。
参与线下互动还有机会获得技术书籍与精美礼品哦!!!
不出意外,这应该是2018年Elastic在杭州的最后一次沙龙,小伙伴们抓紧今年的尾巴,不放过任何学习的机会哦!!!
本次袋鼠云联合阿里云、Elastic 中文社区,共同邀请滴滴、有赞等行业技术专家一同分享和探讨各自领域Elastic的实践。
本次活动时间为12月15日 周六,人数限制100人,大家抓紧报名哈,报名链接https://meetup.elasticsearch.c ... .html。
参与线下互动还有机会获得技术书籍与精美礼品哦!!!
不出意外,这应该是2018年Elastic在杭州的最后一次沙龙,小伙伴们抓紧今年的尾巴,不放过任何学习的机会哦!!! 收起阅读 »
Day 2 - ES 6.x拼音分词高亮爬坑记
首先简单讲下背景~可能在很多公司的很多部门,都有使用到ES。包括在尚德,由于很多部门的业务都涉及到ES,于是我们为了统一管理及维护,专门成立了ES平台部门,主要扮演的是类似于op dba角色,帮助业务部门部署维护ES集群,并根据业务需求提供解决方案。当然,除此之外,我们也会在公司内部推荐业务方去尝试除了日志和搜索以外的应用场景,比如分布式计算存储、监控、安全等方面。毕竟ES相比于其他组建,搭建部署更加方便,更轻量级,查询方式更丰富。所以,现如今在尚德机构,ES平台不仅用于了传统的日志和搜索领域,也在分布式数据存储和计算方面有很多应用。当然,这里只是为大家提供一些ES应用场景及其团队构建的思路。主要还是ES这个工具确实好用。
广告先做到这,回到正文。所以,前段日子,我们接收了一个新的业务部门需求,大致是:他们之前使用的自己搭建ES 2.x集群,现在接入到我们6.x的平台上来。我们帮忙设计了mapping,数据写入及同步方案之后,数据就慢慢接入进来。但问题也随即出现,原来在2.x上使用正常的拼音高亮mapping,在6.x上只能检索但无法高亮了?
2.x field如下:
"index" : {
"analysis" : {
"analyzer" : {
"pinyin_analyzer" : {
"tokenizer" : "my_pinyin"
}
},
"tokenizer" : {
"my_pinyin" : {
"type" : "pinyin",
"keep_full_pinyin" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term":true,
"keep_first_letter":true,
"keep_separate_first_letter" :true
}
}
}
}
POST /medcl/doc/_mapping
{
"properties": {
"name":{
"analyzer": "pinyin_analyzer",
"type": "string"
}
}
}
可以从上面例子看出,这个analyzer并没有问题,但是在搜索时,能得到结果,却无法高亮,即分词结果中start_offset及end_offset为0,这个如何解决呢?
回到medcl的拼音分词项目:
https://github.com/medcl/elast ... inyin
其中,有个配置项引起了我们的注意:
没跑了,应该是要将这个参数设置为false。
并且查看了源码,在PinyinTokenizer这个类下面,看到了这一行:
确定了我们的思路,于是乎,在tokenizer中将此参数设为false,如下:
"tokenizer" : {
"my_pinyin" : {
"type" : "pinyin",
"keep_full_pinyin" : true,
"keep_original" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term":true,
"ignore_pinyin_offset": false,
"keep_first_letter":true,
"keep_separate_first_letter" :true
}
}
写入一条数据,高亮没问题了,问题“看似”解决了。
当然,没有那么简单。因为在批量写入一部分数据后,总会报如下异常:
startOffset must be non-negative, and endOffset must be >= startOffset
这个异常,导致数据无法写入集群。
这里又是为什么呢?
这个问题,我也搞了一段时间,始终没找到很好的解决方案,此处只能先@medcl。
只是猜测在end()或者reset()方法内,需要lastOffset置0或者offsetAtt清空。但尝试了几次,依然报错。。。
这就比较头疼了,不过好在条条道路通罗马。在某次蹲坑过程中,灵感如尿崩。
如果Tokenizer解决不了,为何不仅用filter就行了呢?可以先用其他分词器,按我们业务的需求进行分词,再用filter,将分词过滤为拼音呢?
大致思路如下:
目前我们这个业务,需要如对于“尚德机构”这个词,搜索“shang”,“shangde”,“deji”时,能返回结果并高亮。
所以我们先用ngram分词,将“尚德机构”这个词分为“尚”,“尚德”,“徳机”,“德机构”等等。。
再用pinyin filter将各分词过滤为拼音,即“shang”,“shangde”,“deji”等。
并在搜索时,采用standard分词。
Mapping如下:
{
"settings": {
"analysis": {
"analyzer": {
"pinyin_analyzer": {
"tokenizer": "my_ngram",
"filter": [
"pinyin_filter"
]
}
},
"tokenizer": {
"my_ngram": {
"type": "ngram",
"min_gram": 1,
"max_gram": 50,
"token_chars": [
"letter",
"digit",
"punctuation",
"symbol"
]
}
},
"filter": {
"pinyin_filter": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_none_chinese_in_joined_full_pinyin": true,
"none_chinese_pinyin_tokenize": false,
"remove_duplicated_term": true
}
}
}
},
"mappings": {
"abia321": {
"properties": {
"name": {
"type": "text",
"analyzer": "pinyin_analyzer",
"search_analyzer": "standard",
"term_vector": "with_positions_offsets"
}
}
}
}
}
最后,高亮问题解决,数据写入问题同样解决。
当然有朋友肯定还会需要搜索拼音首字母进行搜索,如搜“s”,“sd”,“dj”,也返回结果。
其实,只需要再专门设置个field,并调整pinyin filter参数,
搜索时用bool查询,逻辑should查询,同时对完整拼音field和拼音首字母field进行搜索即可。
在此就不做过多赘述。
当然,这里仅仅只是提供一种ES在选择analyzer,tokenizer,filter解决需求的思路。拼音分词这个问题,还是需要等待后续修复
最后,这里有较为完整的issue:
https://github.com/medcl/elast ... s/169
首先简单讲下背景~可能在很多公司的很多部门,都有使用到ES。包括在尚德,由于很多部门的业务都涉及到ES,于是我们为了统一管理及维护,专门成立了ES平台部门,主要扮演的是类似于op dba角色,帮助业务部门部署维护ES集群,并根据业务需求提供解决方案。当然,除此之外,我们也会在公司内部推荐业务方去尝试除了日志和搜索以外的应用场景,比如分布式计算存储、监控、安全等方面。毕竟ES相比于其他组建,搭建部署更加方便,更轻量级,查询方式更丰富。所以,现如今在尚德机构,ES平台不仅用于了传统的日志和搜索领域,也在分布式数据存储和计算方面有很多应用。当然,这里只是为大家提供一些ES应用场景及其团队构建的思路。主要还是ES这个工具确实好用。
广告先做到这,回到正文。所以,前段日子,我们接收了一个新的业务部门需求,大致是:他们之前使用的自己搭建ES 2.x集群,现在接入到我们6.x的平台上来。我们帮忙设计了mapping,数据写入及同步方案之后,数据就慢慢接入进来。但问题也随即出现,原来在2.x上使用正常的拼音高亮mapping,在6.x上只能检索但无法高亮了?
2.x field如下:
"index" : {
"analysis" : {
"analyzer" : {
"pinyin_analyzer" : {
"tokenizer" : "my_pinyin"
}
},
"tokenizer" : {
"my_pinyin" : {
"type" : "pinyin",
"keep_full_pinyin" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term":true,
"keep_first_letter":true,
"keep_separate_first_letter" :true
}
}
}
}
POST /medcl/doc/_mapping
{
"properties": {
"name":{
"analyzer": "pinyin_analyzer",
"type": "string"
}
}
}
可以从上面例子看出,这个analyzer并没有问题,但是在搜索时,能得到结果,却无法高亮,即分词结果中start_offset及end_offset为0,这个如何解决呢?
回到medcl的拼音分词项目:
https://github.com/medcl/elast ... inyin
其中,有个配置项引起了我们的注意:
没跑了,应该是要将这个参数设置为false。
并且查看了源码,在PinyinTokenizer这个类下面,看到了这一行:
确定了我们的思路,于是乎,在tokenizer中将此参数设为false,如下:
"tokenizer" : {
"my_pinyin" : {
"type" : "pinyin",
"keep_full_pinyin" : true,
"keep_original" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"remove_duplicated_term":true,
"ignore_pinyin_offset": false,
"keep_first_letter":true,
"keep_separate_first_letter" :true
}
}
写入一条数据,高亮没问题了,问题“看似”解决了。
当然,没有那么简单。因为在批量写入一部分数据后,总会报如下异常:
startOffset must be non-negative, and endOffset must be >= startOffset
这个异常,导致数据无法写入集群。
这里又是为什么呢?
这个问题,我也搞了一段时间,始终没找到很好的解决方案,此处只能先@medcl。
只是猜测在end()或者reset()方法内,需要lastOffset置0或者offsetAtt清空。但尝试了几次,依然报错。。。
这就比较头疼了,不过好在条条道路通罗马。在某次蹲坑过程中,灵感如尿崩。
如果Tokenizer解决不了,为何不仅用filter就行了呢?可以先用其他分词器,按我们业务的需求进行分词,再用filter,将分词过滤为拼音呢?
大致思路如下:
目前我们这个业务,需要如对于“尚德机构”这个词,搜索“shang”,“shangde”,“deji”时,能返回结果并高亮。
所以我们先用ngram分词,将“尚德机构”这个词分为“尚”,“尚德”,“徳机”,“德机构”等等。。
再用pinyin filter将各分词过滤为拼音,即“shang”,“shangde”,“deji”等。
并在搜索时,采用standard分词。
Mapping如下:
{
"settings": {
"analysis": {
"analyzer": {
"pinyin_analyzer": {
"tokenizer": "my_ngram",
"filter": [
"pinyin_filter"
]
}
},
"tokenizer": {
"my_ngram": {
"type": "ngram",
"min_gram": 1,
"max_gram": 50,
"token_chars": [
"letter",
"digit",
"punctuation",
"symbol"
]
}
},
"filter": {
"pinyin_filter": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_none_chinese_in_joined_full_pinyin": true,
"none_chinese_pinyin_tokenize": false,
"remove_duplicated_term": true
}
}
}
},
"mappings": {
"abia321": {
"properties": {
"name": {
"type": "text",
"analyzer": "pinyin_analyzer",
"search_analyzer": "standard",
"term_vector": "with_positions_offsets"
}
}
}
}
}
最后,高亮问题解决,数据写入问题同样解决。
当然有朋友肯定还会需要搜索拼音首字母进行搜索,如搜“s”,“sd”,“dj”,也返回结果。
其实,只需要再专门设置个field,并调整pinyin filter参数,
搜索时用bool查询,逻辑should查询,同时对完整拼音field和拼音首字母field进行搜索即可。
在此就不做过多赘述。
当然,这里仅仅只是提供一种ES在选择analyzer,tokenizer,filter解决需求的思路。拼音分词这个问题,还是需要等待后续修复
最后,这里有较为完整的issue:
https://github.com/medcl/elast ... s/169 收起阅读 »
社区日报 第466期 (2018-12-02)
http://t.cn/ELDJY7y
2.什么是软件工程中的管道? Deployment,CI和CD管道简介。
http://t.cn/ELDcM82
3.(自备梯子)现在是时候认真对待Regulating Tech了。
http://t.cn/ELOozoo
编辑:至尊宝
归档:https://elasticsearch.cn/article/6165
订阅:https://tinyletter.com/elastic-daily
http://t.cn/ELDJY7y
2.什么是软件工程中的管道? Deployment,CI和CD管道简介。
http://t.cn/ELDcM82
3.(自备梯子)现在是时候认真对待Regulating Tech了。
http://t.cn/ELOozoo
编辑:至尊宝
归档:https://elasticsearch.cn/article/6165
订阅:https://tinyletter.com/elastic-daily 收起阅读 »
社区日报 第465期 (2018-12-01)
-
适用于ES 6.0之后的Field Stats插件。 http://t.cn/ELmZMFl
-
你知道ICU分析器支持emoji表情了吗?。 http://t.cn/ELmw4aF
- Canvas中数据表和调试元素的使用示例。 http://t.cn/ELmX7Tc
-
适用于ES 6.0之后的Field Stats插件。 http://t.cn/ELmZMFl
-
你知道ICU分析器支持emoji表情了吗?。 http://t.cn/ELmw4aF
- Canvas中数据表和调试元素的使用示例。 http://t.cn/ELmX7Tc
Day 1 - ELK 使用小技巧(第 3 期)
ELK Tips 主要介绍一些 ELK 使用过程中的小技巧,内容主要来源为 Elastic 中文社区。
一、Logstash
1、Filebeat 设置多个 output
在 6.0 之前,Filebeat 可以设置多个输出(必须是不同类型的输出);从 6.0 开始已经禁止多输出了,只能拥有一个输出,如果想实现多输出,可以借助 logstash 等中间组件进行输出分发。
二、Elasticsearch
1、ES 用户占用的内存大于为 ES 设置的 heapsize
ES 是 Java 应用,底层存储引擎是基于 Lucene 的,heapsize 设置的是 Java 应用的内存;而 Lucene 建立倒排索引(Inverted Index)是先在内存里生成,然后定期以段文件(segment file)的形式刷到磁盘的,因此 Lucene 也会占用一部分内存。
2、ES 使用别名插入数据
ES 可以通过索引的方式向索引插入数据,但是同时只能有一个索引可以被写入,而且需要手动设置,未设置的情况下会报错:no write index is defined for alias [xxxx], The write index may be explicitly disabled using is_write_index=false
or the alias points to multiple indices without one being designated as a write index。
POST /_aliases
{
"actions" : [
{
"add" : {
"index" : "test",
"alias" : "alias1",
"is_write_index" : true
}
}
]
}
3、ES 设置 G1 垃圾回收
修改 jvm.options
文件,将下面几行:
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
改为
-XX:+UseG1GC
-XX:MaxGCPauseMillis=50
即可。
其中 -XX:MaxGCPauseMillis
是控制预期的最高 GC 时长,默认值为 200ms,如果线上业务特性对于 GC 停顿非常敏感,可以适当设置低一些。但是这个值如果设置过小,可能会带来比较高的 cpu 消耗。
4、ES 和 Zipkin 集成时设置验证信息
java -DKAFKA_ZOOKEEPER=10.14.123.117:2181
-DSTORAGE_TYPE=elasticsearch
-DES_HOSTS=http://10.14.125.5:9200
ES_USERNAME=xxx ES_PASSWORD=xxx
-jar zipkin.jar
5、ES 集群部署报错
问题 1 报错信息如下:
Received message from unsupported version:[2.0.0] minimal compatible version is:[5.6.0]
经排查是集群中存在低版本的 ES 实例,将低版本实例移除即可。
问题 2 报错信息如下:
with the same id but is a different node instance
删除对应节点 elsticsearch 文件夹下的 data 文件夹下的节点数据即可。
6、海量中文分词插件
海量分词是天津海量信息技术股份有限公司自主研发的中文分词核心,经测试分词效果还是不错的,值得一试。
7、查询一个索引下的所有 type 名
通过下面的 API,即可获取全部的 type,下面的例子中 doc 就是 indexName 索引下的一个 type:
GET http://es127.0.0.1:9200/indexName/_mappings
-----------------------------------------------
{
indexName: - {
mappings: - {
doc: - {
_all: + {... },
dynamic_date_formats: + [... ],
dynamic_templates: + [... ],
properties: + {... }
}
}
}
}
8、索引模板中根据字段值设置别名
设置索引模板的时候,别名可以使用 Query 条件来进行匹配。
PUT _template/template_1
{
"index_patterns" : ["te*"],
"settings" : {
"number_of_shards" : 1
},
"aliases" : {
"alias2" : {
"filter" : {
"term" : {"user" : "kimchy" }
},
"routing" : "kimchy"
},
"{index}-alias" : {}
}
}
9、索引模板设置默认时间匹配格式
ES 默认是不会将 yyyy-MM-dd HH:mm:ss 识别为时间的,可以通过在索引模板进行如下设置实现多种时间格式的识别:
"mappings": {
"doc": {
"dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss||strict_date_optional_time||epoch_millis"],
10、ES 中 Merge 相关设置
Merge 是非常耗费 CPU 的操作;而且如果不是 SSD 的话,推荐将 index.merge.scheduler.max_thread_count 设置为 1;否则 ES 会启动 Math.min(3, Runtime.getRuntime().availableProcessors() / 2) 个线程进行 Merge 操作;这样大部分机械硬盘的磁盘 IO 都很难承受,就可能出现阻塞。
"index": {
"refresh_interval": "5s",
"number_of_shards": "3",
"max_result_window": 10000,
"translog": {
"flush_threshold_size": "500mb",
"sync_interval": "30s",
"durability": "async"
},
"merge": {
"scheduler": {
"max_merge_count": "100",
"max_thread_count": "1"
}
},
11、mapping 中 enabled store index 参数
- enabled:默认是true,只用于 mapping 中的 object 字段类型;当设置为 false 时,其作用是使 es 不去解析该字段,并且该字段不能被查询和 store,只有在 source 中才能看到,设置 enabled 为 false,可以不设置字段类型,默认类型为 object;
- store:默认 false,store 参数的功能和 source 有一些相似,我们的数据默认都会在 source 中存在,但我们也可以将数据 store 起来;当我们使用
copy_to
参数时,copy_to
的目标字段并不会在 source 中存储,此时 store 就派上用场了; - index:默认是 true,当设置为 false,表明该字段不能被查询,如果查询会报错。
12、ES 图片搜索
- 可以借助局部敏感 LSH 或者 pHash 来实现:https://stackoverflow.com/questions/32785803
- Github 也有一个开源项目使用了多种 Hash 算法借助 ES 来实现图片搜索:https://github.com/usc-isi-i2/elasticsearch-image-features
13、Term 聚合根据子聚合结果排序
GET /_search
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "playback_stats.max" : "desc" }
},
"aggs" : {
"playback_stats" : { "stats" : { "field" : "play_count" } }
}
}
}
}
三、社区文章精选
ELK Tips 主要介绍一些 ELK 使用过程中的小技巧,内容主要来源为 Elastic 中文社区。
一、Logstash
1、Filebeat 设置多个 output
在 6.0 之前,Filebeat 可以设置多个输出(必须是不同类型的输出);从 6.0 开始已经禁止多输出了,只能拥有一个输出,如果想实现多输出,可以借助 logstash 等中间组件进行输出分发。
二、Elasticsearch
1、ES 用户占用的内存大于为 ES 设置的 heapsize
ES 是 Java 应用,底层存储引擎是基于 Lucene 的,heapsize 设置的是 Java 应用的内存;而 Lucene 建立倒排索引(Inverted Index)是先在内存里生成,然后定期以段文件(segment file)的形式刷到磁盘的,因此 Lucene 也会占用一部分内存。
2、ES 使用别名插入数据
ES 可以通过索引的方式向索引插入数据,但是同时只能有一个索引可以被写入,而且需要手动设置,未设置的情况下会报错:no write index is defined for alias [xxxx], The write index may be explicitly disabled using is_write_index=false
or the alias points to multiple indices without one being designated as a write index。
POST /_aliases
{
"actions" : [
{
"add" : {
"index" : "test",
"alias" : "alias1",
"is_write_index" : true
}
}
]
}
3、ES 设置 G1 垃圾回收
修改 jvm.options
文件,将下面几行:
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
改为
-XX:+UseG1GC
-XX:MaxGCPauseMillis=50
即可。
其中 -XX:MaxGCPauseMillis
是控制预期的最高 GC 时长,默认值为 200ms,如果线上业务特性对于 GC 停顿非常敏感,可以适当设置低一些。但是这个值如果设置过小,可能会带来比较高的 cpu 消耗。
4、ES 和 Zipkin 集成时设置验证信息
java -DKAFKA_ZOOKEEPER=10.14.123.117:2181
-DSTORAGE_TYPE=elasticsearch
-DES_HOSTS=http://10.14.125.5:9200
ES_USERNAME=xxx ES_PASSWORD=xxx
-jar zipkin.jar
5、ES 集群部署报错
问题 1 报错信息如下:
Received message from unsupported version:[2.0.0] minimal compatible version is:[5.6.0]
经排查是集群中存在低版本的 ES 实例,将低版本实例移除即可。
问题 2 报错信息如下:
with the same id but is a different node instance
删除对应节点 elsticsearch 文件夹下的 data 文件夹下的节点数据即可。
6、海量中文分词插件
海量分词是天津海量信息技术股份有限公司自主研发的中文分词核心,经测试分词效果还是不错的,值得一试。
7、查询一个索引下的所有 type 名
通过下面的 API,即可获取全部的 type,下面的例子中 doc 就是 indexName 索引下的一个 type:
GET http://es127.0.0.1:9200/indexName/_mappings
-----------------------------------------------
{
indexName: - {
mappings: - {
doc: - {
_all: + {... },
dynamic_date_formats: + [... ],
dynamic_templates: + [... ],
properties: + {... }
}
}
}
}
8、索引模板中根据字段值设置别名
设置索引模板的时候,别名可以使用 Query 条件来进行匹配。
PUT _template/template_1
{
"index_patterns" : ["te*"],
"settings" : {
"number_of_shards" : 1
},
"aliases" : {
"alias2" : {
"filter" : {
"term" : {"user" : "kimchy" }
},
"routing" : "kimchy"
},
"{index}-alias" : {}
}
}
9、索引模板设置默认时间匹配格式
ES 默认是不会将 yyyy-MM-dd HH:mm:ss 识别为时间的,可以通过在索引模板进行如下设置实现多种时间格式的识别:
"mappings": {
"doc": {
"dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss||strict_date_optional_time||epoch_millis"],
10、ES 中 Merge 相关设置
Merge 是非常耗费 CPU 的操作;而且如果不是 SSD 的话,推荐将 index.merge.scheduler.max_thread_count 设置为 1;否则 ES 会启动 Math.min(3, Runtime.getRuntime().availableProcessors() / 2) 个线程进行 Merge 操作;这样大部分机械硬盘的磁盘 IO 都很难承受,就可能出现阻塞。
"index": {
"refresh_interval": "5s",
"number_of_shards": "3",
"max_result_window": 10000,
"translog": {
"flush_threshold_size": "500mb",
"sync_interval": "30s",
"durability": "async"
},
"merge": {
"scheduler": {
"max_merge_count": "100",
"max_thread_count": "1"
}
},
11、mapping 中 enabled store index 参数
- enabled:默认是true,只用于 mapping 中的 object 字段类型;当设置为 false 时,其作用是使 es 不去解析该字段,并且该字段不能被查询和 store,只有在 source 中才能看到,设置 enabled 为 false,可以不设置字段类型,默认类型为 object;
- store:默认 false,store 参数的功能和 source 有一些相似,我们的数据默认都会在 source 中存在,但我们也可以将数据 store 起来;当我们使用
copy_to
参数时,copy_to
的目标字段并不会在 source 中存储,此时 store 就派上用场了; - index:默认是 true,当设置为 false,表明该字段不能被查询,如果查询会报错。
12、ES 图片搜索
- 可以借助局部敏感 LSH 或者 pHash 来实现:https://stackoverflow.com/questions/32785803
- Github 也有一个开源项目使用了多种 Hash 算法借助 ES 来实现图片搜索:https://github.com/usc-isi-i2/elasticsearch-image-features
13、Term 聚合根据子聚合结果排序
GET /_search
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "playback_stats.max" : "desc" }
},
"aggs" : {
"playback_stats" : { "stats" : { "field" : "play_count" } }
}
}
}
}
三、社区文章精选
- ET007 ElasticStack 6.5 介绍
- CentOS 7.4 下安装 ES 6.5.1 搜索集群
- Elastic Stack v6.5 新特性解读
- Elasticsearch 史上最全最常用工具清单
社区日报 第464期 (2018-11-30)
http://t.cn/ELYKOXo
2、Elasticsearch搜索引擎性能调优实践
http://t.cn/ELRuqLN
3、全文检索ElasticSearch与Spring boot集成实例
http://t.cn/ELRuKal
编辑:铭毅天下
归档:https://elasticsearch.cn/article/6162
订阅:https://tinyletter.com/elastic-daily
http://t.cn/ELYKOXo
2、Elasticsearch搜索引擎性能调优实践
http://t.cn/ELRuqLN
3、全文检索ElasticSearch与Spring boot集成实例
http://t.cn/ELRuKal
编辑:铭毅天下
归档:https://elasticsearch.cn/article/6162
订阅:https://tinyletter.com/elastic-daily
收起阅读 »
社区日报 第463期 (2018-11-29)
http://t.cn/ELp5dHT
2.Lucene 内核解析之Point索引
http://t.cn/ELptLV7
3.部署安全插件searchguard
http://t.cn/ELptMbj
编辑:金桥
归档:https://elasticsearch.cn/article/6161
订阅:https://tinyletter.com/elastic-daily
http://t.cn/ELp5dHT
2.Lucene 内核解析之Point索引
http://t.cn/ELptLV7
3.部署安全插件searchguard
http://t.cn/ELptMbj
编辑:金桥
归档:https://elasticsearch.cn/article/6161
订阅:https://tinyletter.com/elastic-daily 收起阅读 »
社区日报 第462期 (2018-11-28)
1. 让天下没有难用的搜索 阿里搜索如何成长为贴心“暖男”
http://t.cn/E2UjZ6d
2.Elasticsearcharch索引生命周期管理探索
http://t.cn/RDUxF3t
3. 实例展示Elasticsearch集群生态,分片以及水平扩展
http://t.cn/RzIQzrR
编辑:江水
归档:http://elasticsearch.cn/article/6160
订阅:https://tinyletter.com/elastic-daily
1. 让天下没有难用的搜索 阿里搜索如何成长为贴心“暖男”
http://t.cn/E2UjZ6d
2.Elasticsearcharch索引生命周期管理探索
http://t.cn/RDUxF3t
3. 实例展示Elasticsearch集群生态,分片以及水平扩展
http://t.cn/RzIQzrR
编辑:江水
归档:http://elasticsearch.cn/article/6160
订阅:https://tinyletter.com/elastic-daily 收起阅读 »
关于es映射mapping中的enabled,store,index参数的理解
enabled参数:
默认是true。只用于mapping中的object字段类型。当设置为false时,其作用是使es不去解析该字段,并且该字段不能被查询和store,只有在_source中才能看到(即查询结果中会显示的_source数据)。设置enabled为false,可以不设置字段类型,默认为object
index参数:
默认是true。当设置为false,表明该字段不能被查询,如果查询会报错。但是可以被store。当该文档被查出来时,在_source中也会显示出该字段。
store参数:
默认false。store参数的功能和_source有一些相似。我们的数据默认都会在_source中存在。但我们也可以将数据store起来,不过大部分时候这个功能都很鸡肋。不过有一个例外,当我们使用copy_to参数时,copy_to的目标字段并不会在_source中存储,此时store就派上用场了。
三者能否同时存在:
首先设置了enabled为false就不能设置store为true了,这两者冲突。而index和store是不冲突的。最后index和enabled之间的问题:enabled需要字段类型为object,而当字段类型为object时,好像不能设置index参数,试了几次都会报错。
PUT mindex/
{
"mappings": {
"type": {
"properties": {
"name": {
"type": "text",
"copy_to": "name_title",
"store": true,
"index": false
},
"title": {
"type": "text",
"copy_to": "name_title"
},
"name_title": {
"type": "text",
"store": true
},
"notenabled": {
"type": "object",
"enabled": false
}
}
}
}
}
PUT mindex/type/1
{
"name":"zz",
"title":"zxx",
"notenabled":"baby"
}
在搜索中使用了stored_fields之后,_source不会自己出现了,要手动指定字段。stored_fields里面不能出现notenabled。GET /mindex/_search
{
"query": {
"match": {
"title": "zxx"
}
},
"stored_fields": ["name_title","title","name"],
"_source": ["name_title","title","name","notenabled"]
}
结果"_source": {
"name": "zz",
"title": "zxx",
"notenabled": "baby"
},
"fields": {
"name": [
"zz"
],
"name_title": [
"zz",
"zxx"
]
}
看到结果,与上面的分析吻合。
enabled参数:
默认是true。只用于mapping中的object字段类型。当设置为false时,其作用是使es不去解析该字段,并且该字段不能被查询和store,只有在_source中才能看到(即查询结果中会显示的_source数据)。设置enabled为false,可以不设置字段类型,默认为object
index参数:
默认是true。当设置为false,表明该字段不能被查询,如果查询会报错。但是可以被store。当该文档被查出来时,在_source中也会显示出该字段。
store参数:
默认false。store参数的功能和_source有一些相似。我们的数据默认都会在_source中存在。但我们也可以将数据store起来,不过大部分时候这个功能都很鸡肋。不过有一个例外,当我们使用copy_to参数时,copy_to的目标字段并不会在_source中存储,此时store就派上用场了。
三者能否同时存在:
首先设置了enabled为false就不能设置store为true了,这两者冲突。而index和store是不冲突的。最后index和enabled之间的问题:enabled需要字段类型为object,而当字段类型为object时,好像不能设置index参数,试了几次都会报错。
PUT mindex/
{
"mappings": {
"type": {
"properties": {
"name": {
"type": "text",
"copy_to": "name_title",
"store": true,
"index": false
},
"title": {
"type": "text",
"copy_to": "name_title"
},
"name_title": {
"type": "text",
"store": true
},
"notenabled": {
"type": "object",
"enabled": false
}
}
}
}
}
PUT mindex/type/1
{
"name":"zz",
"title":"zxx",
"notenabled":"baby"
}
在搜索中使用了stored_fields之后,_source不会自己出现了,要手动指定字段。stored_fields里面不能出现notenabled。GET /mindex/_search
{
"query": {
"match": {
"title": "zxx"
}
},
"stored_fields": ["name_title","title","name"],
"_source": ["name_title","title","name","notenabled"]
}
结果"_source": {
"name": "zz",
"title": "zxx",
"notenabled": "baby"
},
"fields": {
"name": [
"zz"
],
"name_title": [
"zz",
"zxx"
]
}
看到结果,与上面的分析吻合。 收起阅读 »