初识 ElasticSearch

场景:最近有同事分享了ElasticSearch Inverted Index,因此本身也了解一下基于Lucene的ES。node

转载自:http://www.jianshu.com/p/05cff717563cpython

Why Elasticsearch?

因为须要提高项目的搜索质量,最近研究了一下Elasticsearch,一款很是优秀的分布式搜索程序。最开始的一些笔记放到github,这里只是概括总结一下。mysql

首先,为何要使用Elasticsearch?最开始的时候,咱们的项目仅仅使用MySQL进行简单的搜索,而后一个不能索引的like语句,直接拉低MySQL的性能。后来,咱们曾考虑过sphinx,而且sphinx也在以前的项目中成功实施过,但想一想如今的数据量级,多台MySQL,以及搜索服务自己HA,还有后续扩容的问题,咱们以为sphinx并非一个最优的选择。因而天然将目光放到了Elasticsearch上面。git

根据官网本身的介绍,Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard的方式保证数据安全,而且提供自动resharding的功能,加之github等大型的站点也采用Elasticsearch做为其搜索服务,咱们决定在项目中使用Elasticsearch。github

对于Elasticsearch,若是要在项目中使用,须要解决以下问题:算法

  1. 索引,对于须要搜索的数据,如何创建合适的索引,还须要根据特定的语言使用不一样的analyzer等。
  2. 搜索,Elasticsearch提供了很是强大的搜索功能,如何写出高效的搜索语句?
  3. 数据源,咱们全部的数据是存放到MySQL的,MySQL是惟一数据源,如何将MySQL的数据导入到Elasticsearch?

对于1和2,由于咱们的数据都是从MySQL生成,index的field是固定的,主要作的工做就是根据业务场景设计好对应的mapping以及search语句就能够了,固然实际不可能这么简单,须要咱们不断的调优。sql

而对于3,则是须要一个工具将MySQL的数据导入Elasticsearch,由于咱们对搜索实时性要求很高,因此须要将MySQL的增量数据实时导入,笔者惟一能想到的就是经过row based binlog来完成。而近段时间的工做,也就是实现一个MySQL增量同步到Elasticsearch的服务。数据库

Lucene

Elasticsearch底层是基于Lucene的,Lucene是一款优秀的搜索lib,固然,笔者之前仍然没有接触使用过。编程

Lucene关键概念:json

  • Document:用来索引和搜索的主要数据源,包含一个或者多个Field,而这些Field则包含咱们跟Lucene交互的数据。
  • Field:Document的一个组成部分,有两个部分组成,name和value。
  • Term:不可分割的单词,搜索最小单元。
  • Token:一个Term呈现方式,包含这个Term的内容,在文档中的起始位置,以及类型。

Lucene使用Inverted index来存储term在document中位置的映射关系。
譬如以下文档:

  • Elasticsearch Server 1.0 (document 1)
  • Mastring Elasticsearch (document 2)
  • Apache Solr 4 Cookbook (document 3)

使用inverted index存储,一个简单地映射关系:

Term Count Docuemnt
1.0 1 <1>
4 1 <3>
Apache 1 <3>
Cookbook 1 <3>
Elasticsearch 2 <1>.<2>
Mastering 1 <2>
Server 1 <1>
Solr 1 <3>

对于上面例子,咱们首先经过分词算法将一个文档切分红一个一个的token,再获得该token与document的映射关系,并记录token出现的总次数。这样就获得了一个简单的inverted index。

Elasticsearch关键概念

要使用Elasticsearch,笔者认为,只须要理解几个基本概念就能够了。

在数据层面,主要有:

  • Index:Elasticsearch用来存储数据的逻辑区域,它相似于关系型数据库中的db概念。一个index能够在一个或者多个shard上面,同时一个shard也可能会有多个replicas。
  • Document:Elasticsearch里面存储的实体数据,相似于关系数据中一个table里面的一行数据。
    document由多个field组成,不一样的document里面同名的field必定具备相同的类型。document里面field能够重复出现,也就是一个field会有多个值,即multivalued。
  • Document type:为了查询须要,一个index可能会有多种document,也就是document type,但须要注意,不一样document里面同名的field必定要是相同类型的。
  • Mapping:存储field的相关映射信息,不一样document type会有不一样的mapping。

对于熟悉MySQL的童鞋,咱们只须要大概认为Index就是一个db,document就是一行数据,field就是table的column,mapping就是table的定义,而document type就是一个table就能够了。

Document type这个概念其实最开始也把笔者给弄糊涂了,其实它就是为了更好的查询,举个简单的例子,一个index,可能一部分数据咱们想使用一种查询方式,而另外一部分数据咱们想使用另外一种查询方式,因而就有了两种type了。不过这种状况应该在咱们的项目中不会出现,因此一般一个index下面仅会有一个type。

在服务层面,主要有:

  • Node: 一个server实例。
  • Cluster:多个node组成cluster。
  • Shard:数据分片,一个index可能会存在于多个shards,不一样shards可能在不一样nodes。
  • Replica:shard的备份,有一个primary shard,其他的叫作replica shards。

Elasticsearch之因此能动态resharding,主要在于它最开始就预先分配了多个shards(貌似是1024),而后以shard为单位进行数据迁移。这个作法其实在分布式领域很是的广泛,codis就是使用了1024个slot来进行数据迁移。

由于任意一个index均可配置多个replica,经过冗余备份的方式保证了数据的安全性,同时replica也能分担读压力,相似于MySQL中的slave。

Restful API

Elasticsearch提供了Restful API,使用json格式,这使得它很是利于与外部交互,虽然Elasticsearch的客户端不少,但笔者仍然很容易的就写出了一个简易客户端用于项目中,再次印证了Elasticsearch的使用真心很容易。

Restful的接口很简单,一个url表示一个特定的资源,譬如/blog/article/1,就表示一个index为blog,type为aritcle,id为1的document。

而咱们使用http标准method来操做这些资源,POST新增,PUT更新,GET获取,DELETE删除,HEAD判断是否存在。

这里,友情推荐httpie,一个很是强大的http工具,我的感受比curl还用,几乎是命令行调试Elasticsearch的绝配。

一些使用httpie的例子:

# create http POST :9200/blog/article/1 title="hello elasticsearch" tags:='["elasticsearch"]' # get http GET :9200/blog/article/1 # update http PUT :9200/blog/article/1 title="hello elasticsearch" tags:='["elasticsearch", "hello"]' # delete http DELETE :9200/blog/article/1 # exists http HEAD :9200/blog/article/1

索引和搜索

虽然Elasticsearch能自动判断field类型并创建合适的索引,但笔者仍然推荐本身设置相关索引规则,这样才能更好为后续的搜索服务。

咱们经过定制mapping的方式来设置不一样field的索引规则。

而对于搜索,Elasticsearch提供了太多的搜索选项,就不一一律述了。

索引和搜索是Elasticsearch很是重要的两个方面,直接关系到产品的搜索体验,但笔者现阶段也仅仅是大概了解了一点,后续在详细介绍。

同步MySQL数据

Elasticsearch是很强大,但要创建在有足量数据状况下面。咱们的数据都在MySQL上面,因此如何将MySQL的数据导入Elasticsearch就是笔者最近研究的东西了。

虽然如今有一些实现,譬如elasticsearch-river-jdbc,或者elasticsearch-river-mysql,但笔者并不打算使用。

elasticsearch-river-jdbc的功能是很强大,但并无很好的支持增量数据更新的问题,它须要对应的表只增不减,而这个几乎在项目中是不可能办到的。

elasticsearch-river-mysql却是作的很不错,采用了python-mysql-replication来经过binlog获取变动的数据,进行增量更新,但它貌似处理MySQL dump数据导入的问题,不过这个笔者真的好好确认一下?话说,python-mysql-replication笔者还提交过pull解决了minimal row image的问题,因此对elasticsearch-river-mysql这个项目颇有好感。只是笔者决定本身写一个出来。

为何笔者决定本身写一个,不是由于笔者喜欢造轮子,主要缘由在于对于这种MySQL syncer服务(增量获取MySQL数据更新到相关系统),咱们不光能够用到Elasticsearch上面,并且还能用到其余服务,譬如cache上面。因此笔者其实想实现的是一个通用MySQL syncer组件,只是如今主要关注Elasticsearch罢了。

项目代码在这里go-mysql-elasticsearch,现已完成第一阶段开发,内部对接测试中。

go-mysql-elasticsearch的原理很简单,首先使用mysqldump获取当前MySQL的数据,而后在经过此时binlog的name和position获取增量数据。

一些限制:

  • binlog必定要变成row-based format格式,其实咱们并不须要担忧这种格式的binlog占用太多的硬盘空间,MySQL 5.6以后GTID模式都推荐使用row-based format了,并且一般咱们都会把控SQL语句质量,不容许一次性更改过多行数据的。
  • 须要同步的table最好是innodb引擎,这样mysqldump的时候才不会阻碍写操做。
  • 须要同步的table必定要有主键,好吧,若是一个table没有主键,笔者真心会怀疑设计这个table的同窗编程水平了。多列主键也是不推荐的,笔者现阶段不打算支持。
  • 必定别动态更改须要同步的table结构,Elasticsearch只能支持动态增长field,并不支持动态删除和更改field。一般来讲,若是涉及到alter table,不少时候已经证实前期设计的不合理以及对于将来扩展的预估不足了。

更详细的说明,等到笔者完成了go-mysql-elasticsearch的开发,并经过生产环境中测试了,再进行补充。

总结

对于一门不懂的技术,找一份靠谱的资料(官方文档或者入门书籍),蛋疼的对着资料敲一遍代码,不懂的再问google,最后在将其用到实际项目,这门技术就算是初步掌握了,固然精通还得在下点功夫。

相关文章
相关标签/搜索