发表日期:2019年9月18日
ElasticSearch是一个集数据存储、数据搜索和数据分析为一体的系统。它是分布式的,所以能利用分布式来提高其处理能力,具有高可用性和高伸缩性。如果你需要一个能够提供高性能的搜索服务的系统,那么它或许是一个好的选择。
ElasticSearch是一个搜索系统,搜索就是从数据集合中搜索出我们想要的数据,例如从大量的商品数据中搜索出我们想要的某类商品。
现在提一个需求,例如我有一个“文章”的表,我想搜索文章表中字段content中包含有'java'的数据。
如果你不使用ES,那么从开发角度来说,平常我们都是使用关系型数据库系统来存储数据,然后使用类似select name,age,address from student where name like '%李%'
的语句通过模糊匹配来搜索符合指定条件的数据的。(对应到上面的需求应该是select name,author,content from article where content like '%java%'
)但其实上面这种基于模糊匹配的搜索方式的效率是比较低的,因为数据库系统的搜索通常是逐一扫描的,也就是从头到尾的来尝试匹配,某个字段的数据越多,可能需要尝试匹配的次数就会越多(试想一下从4000字的文章中从上到下只为找到一个字),这种查找就好像最低级的遍历查找(当然并不是真的就是傻傻的遍历了,各个数据库系统都会采用各种算法来优化)。
而ElasticSearch由于其内部建立了每个词的索引表,当搜索某个词时,可以根据这个词从索引表中找到匹配的记录,所以效率比较高(就好像记录了某个词的坐标,有了坐标,就能根据坐标非常快地找到那个词)。
(这里举个类似的栗子:相信大家都用过字典,那么普通的数据库搜索就好像从第一页到最后一页找一个词,而ElasticSearch根据这个词的部首结构从“部首-字的对应表”中直接查找到那个字的页数,这个效率直接就是天差地别了!)另外,数据库的搜索是根据指定词直接查找的,它是很笨的!它不能查找到某些意义上“类似”的结果,比如我搜索“mother”,但如果某个记录中包含“mom”这个词,那这条记录也应该被展示出来,而数据库的普通搜索做不到。
而这个操作ElasticSearch就可以做到,由于它内部有分词器,在建立索引的过程中,分词器可以把数据中的某些词都认为是指定的某一个词(比如把mother,mom通通都使用mom作为索引词),再用这个词来建立索引,然后在进行搜索的时候,将输入的词也进行同样的转化,再根据这个词从索引表中查找到符合的记录结果,这样就可以把那些意义相近的结果也搜索出来。所以说,ElasticSearch解决了普通全文搜索的搜索效率低下和搜索不智能的问题。
介绍两个搜索方法:顺序扫描查找、全文搜索
上面有说到数据库的搜索和ElasticSearch的搜索。
常见的关系型数据库的针对某个字段中的数据的搜索是顺序扫描查找,从头到尾去尝试匹配,也就是所谓的遍历查找,当然算法可能没有那么低级。(现在一些数据库系统也在尝试优化全文搜索功能。)而ElasticSearch的搜索是全文搜索,而什么是全文搜索?
全文搜索可以根据一定方式把非结构化的数据对应到一种结构化的标识,从而可以通过标识来检索到指定的非结构化的数据记录。
这句话可能有点难以理解,举个例子理解,比如有一大堆食物你需要去认识,食物本身可以被认作是非结构化的数据,因为他们都是独特的,但如果我们利用他们的颜色来划分的话就可以初步地将他们进行结构化划分,这个就是一种简单的将数据结构化的手段。在ElasticSearch中,这个把非结构化的数据对应到一种结构化的标识的方式就是倒排索引,下面介绍倒排索引来理解这个概念。在ElasticSearch中,处理这些非结构化的数据的方式就是建立倒排索引(Inverted Index)。
什么是倒排索引呢?
倒排索引把数据进行了拆分(比如某个字段的数据为hello world,那么就会被拆分成hello和world),我们使用这些拆分的词来作为索引词来建立索引表,在以hello为索引词的记录中,有对hello world
的指向,world也是如此。
当然,这里的拆分并不是真实的拆分,原始的数据依然存储在elasticsearch中,我们另外创建了一个索引文件来存储。下面是一个使用倒排索引搜索的示例
1.首先,假设我们有一个字段的数据是"I thank my mother",当我们把这个数据存储到ElasticSearch中,ElasticSearch内部使用分词器进行处理数据,分词器用于将非结构化数据中的词进行拆分和转换,于是把"I thank my mother"拆解成了"I"、"thank"、"my"、"mother"。
2.当把数据拆分出来后(拆分成的数据单位我们称为“词”),就会把这些词建立索引,ElasticSearch内部有一个索引表,用于建立词与数据的对应,结构类似如下(真实格式还会有词的频率、数据长度等信息),索引表存储了词和词所在记录的ID集合,所以可以通过某个词来快速搜索出相关的记录,比如搜索"I",那么会返回1和2,然后可以快速根据ID来获取对应的数据。【请注意,下图只是方便理解,并不是真实的格式】
3.然后我们搜索的时候,分词器也先把我们输入的内容处理(为了与索引表的词统一),然后再从索引表中查找,返回对应的数据记录集合。
例如我输入mother,mother会先转成mom,然后从索引表中找到mom,返回包含mom的记录的ID,然后根据ID获取对应数据,也就是“I like my mom”
Lucene也是一种搜索引擎,为什么不直接使用Lucene?
ElasticSearch实际上底层使用的就是Lucene,虽然Lucene也有很多功能,但Lucene的使用难度较大(也正是使用难度高所以ElasticSearch才对Lucene进行封装),而且ElasticSearc的高级功能也很强大,ES支持了多样的数据分析。除了基本的功能,集群能力也是一个问题,Lucene一开始没有考虑集群,所以对于存储在不同服务器上的大量数据的交互比较麻烦,而ElasticeSearch一开始就是集群思想的,数据存储以一个ElasticSearch节点为单位,多个节点的数据可以交流。
由于底层是Lucene,所以,对于一些elasticsearch底层的东西,有时候你完全可以参照Lucene,比如索引词文件的存储等。为什么不是Solr?
Solr也是一个知名的搜索引擎,它与ElasticSearch各有好处,Solr适用于一些非实时搜索系统(新增的数据不要求马上查出来的),而ElasticSearch适用于一些实时搜索要求较高的系统(电商平台等要求新商品马上可查的系统)。因为Solr在建立索引时,搜索效率下降,实时索引搜索效率不高,而ElasticSearch建立索引的速度较快。ElasticSearch有一个非常显著的特性"NRT":NRT全称Near Real Time,近实时,意思是你插入的数据几乎可以“马上”就可以被搜索出来。这也是为什么它能使用在实时更新要求高的场景的原因。
上面提了词的拆分,这里提一些关于底层的搜索处理的内容。介绍一下ElasticSearch另一个协助搜索的关键组件--分词器。ElasticSearch的全文搜索离不开分词器的帮助。
分词器通常由分解器tokenizer和词元过滤器token filter组成。
分词器对数据的分词处理:为了提高索引的效率,ElasticSearch会数据进行处理,处理方式主要有字符过滤、词转换、词拆分
字符过滤:过滤一些特殊字符,例如&
、||
、html标签,因为这些词通常搜索意义不大。词转换:把一些意义相同的词统一转成一个词,(同词义转换)比如mom,mother统一转成mom;(大小写转换)he,He统一归为He;还处理一些词意义不大的词(停用词清除),比如英文的“the”,“to”,这些词使用频率很高,但没有具体意义。
词拆分:进行数据的拆分,拆分成词,比如把
good morning,mom
拆分成good
,morining
,mom
。另外,词拆分并不完全是按照数据的最小单位分解的,某一些分词器会把一些词进行组合,因为一些词的组合起来才有索引的意义,比如中文的一些词通常要组合起来才有意义,比如“大”和“家”要组成“大家”才有比较具体的意义,这是为了确保索引词的最小单位是有意义的(比如英文mom的最小单位是m,o,m,内部的分词器要能够区分出mom整个是有意义的才可以确保是采用mom作为索引,而不是采用m和o,也正是因为这个问题,所以英文分词器不能用于中文分词器)。【分词器有很多个,默认的分词器是不能适当对中文数据分词的,它只能把一个个数据按最小的单位拆分,因为英文分词器不能分清楚怎么把词拆分才有意义,由于配置分词器是一个较为靠后的知识点,所以前期将以英文数据为测试数据。】分词文件的存储:
分词文件一般包括三种文件:词典文件,频率文件,位置文件。
词典文件保存了关键词(索引词),还保留了指向频率文件和位置文件的指针。
频率文件记录了词出现的频率。
位置文件记录了这些词出现在哪些数据中。
首先要说的是,ElasticSearch是一款软件,有点类似MySQL,我们要操作它的时候,也要给它发送它能识别的命令,而ElasticSearch是面向restful(不知道restful的自查吧)的,所以我们发送的命令是有点类似发送http请求的。
mysql是3306端口,而elasticsearch支持9200和9300端口操作,其中9200面向http,9300面向tcp。9200能够使用普通的http请求来操作elasticsearch,9300需要连接elasticsearch之后再执行命令。
下载:
安装:
运行:
elasticsearch-6.2.0\bin
中运行elasticsearch.bat
,当提示“started”时,表示运行成功。kibana-6.2.0-windows-x86_64\bin
中运行kibana.bat
,当提示“Server running at http://localhost:5601”时,表示运行成功。【要先运行ElasticSearch再运行Kibana,因为它要与ElasticSearch进行连接】ElasticSearch默认的TCP服务端口是9300,Kibana的服务端口是5601,当我们启动了Kibana之后,它会默认帮我们连接上9300,所以我们可以从http://localhost:5601
中进入Kibana的管理界面来管理ElasticSearch。
如果你是第一次使用,那么ElasticSearch会自动创建一个名为elasticsearch
的集群,Kibana会在这个节点中初始化一个index
我们在Kibana的DevTools中执行一些命令来看一下ElasticSearch。【从http://localhost:5601
中进入】
在输入命令GET /_cat/health?v
后,点击该行右侧的执行按钮。【GET /_cat/health?v
是查看集群的健康状态的命令】
然后就可以在右侧的结果窗口中查看命令执行结果。
【你现在大概都是看不懂命令的意义和结果的意义的了,不过你应该知道哪里输入命令和哪里看执行结果了】
postman是一个用来发请求的软件,可以使用restful风格的请求来操作elasticsearch。
比如上面的查看集群的命令:GET /_cat/health?v
转成基于restful的是:http://localhost:9200/_cat/health?v
即IP:9200+命令
,其中9200是用于接收restful请求的es监听端口。
上面的第一次使用并没有涉及到具体的知识,只是让你熟悉一下如何使用Kibana来操作ElasticSearch。下面讲到具体知识点才会具体使用。
数据存储在shard中,shard中的数据是以文档document为单位的。document存储在index和type划分的逻辑空间中。document以json为格式,每一个key-value中key可以称为域Field。
{ "book_id": 1, "book_name": "Java Core ", "book_desc": "A good book, you know!", "category_id": "1", "category_name": "Computer" }
请求方法 | 对应操作 | 说明 |
---|---|---|
GET | 读取 | 获取数据 |
POST | 新增 | 新增数据 |
PUT | 修改 | 修改数据或增加数据 |
DELETE | 删除 | 删除数据 |
前面提了一下index,type,document,说了ElasticSearch的逻辑存储空间。
下面以两个实例:“写document->读document”和“写document->搜索document“来初步演示一下如何存储数据和获取数据。
如果我们要向ElasticSearch中写入一份数据(document),命令的语法应该如下:
复制代码PUT /index名称/type名称/document的ID { document的数据 }
上面的语法的意思就是向一个index的一个type中插入一个document,document用id作为标识,后面我们取document的数据也将以这个id为依据。其中index,type是可以不需要我们预创建的,在我们还不会如何创建index和type的时候,你可以先随便打个名字(如果ElasticSearch检测到我们输入的index和type是不存在的,那么它就会以默认的规则帮我们创建出来)。
请在kibana的devtool中执行以下命令来存储一份document:
复制代码PUT /douban/book/1 { "book_id":1, "book_name":"A Clockwork Orange", "author":"Anthony Burgess", "summary":"Fully restored edition of Anthony Burgess' original text of A Clockwork Orange, with a glossary of the teen slang 'Nadsat', explanatory notes, pages from the original typescript, interviews, articles and reviews Edited by Andrew Biswell With a Foreword by Martin Amis 'It is a horrorshow story ...' Fifteen-year-old Alex likes lashings of ultraviolence. He and his gang of friends rob, kill and rape their way through a nightmarish future, until the State puts a stop to his riotous excesses. But what will his re-education mean? A dystopian horror, a black comedy, an exploration of choice, A Clockwork Orange is also a work of exuberant invention which created a new language for its characters. This critical edition restores the text of the novel as Anthony Burgess originally wrote it, and includes a glossary of the teen slang 'Nadsat', explanatory notes, pages from the original typescript, interviews, articles and reviews, shedding light on the enduring fascination of the novel's 'sweet and juicy criminality'. Anthony Burgess was born in Manchester in 1917 and educated at Xaverian College and Manchester University. He spent six years in the British Army before becoming a schoolmaster and colonial education officer in Malaya and Brunei. After the success of his Malayan Trilogy, he became a full-time writer in 1959. His books have been published all over the world, and they include The Complete Enderby, Nothing Like the Sun, Napoleon Symphony, Tremor of Intent, Earthly Powers and A Dead Man in Deptford. Anthony Burgess died in London in 1993. Andrew Biswell is the Professor of Modern Literature at Manchester Metropolitan University and the Director of the International Anthony Burgess Foundation. His publications include a biography, The Real Life of Anthony Burgess, which won the Portico Prize in 2006. He is currently editing the letters and short stories of Anthony Burgess.", "press":"Penguin Classic", "publication_date":"2000-02-22" }
如果要获取ES中存储的document,命令的语法应该如下:
复制代码GET /index名/type名/id
一样的,请在kibana中执行下述命令来获取我们上面存储的document:
复制代码GET /douban/book/1
返回结果:【返回index名称,type名称,id,原始文档等数据】
很明显地,我们获取到了我们刚刚存储进去的数据。
一样的,我们写多一份数据进ES中:
复制代码PUT /douban/book/2 { "book_id":2, "book_name":"Kubernetes in Action", "author":"Marko Luksa", "summary":"Kubernetes in Action teaches you to use Kubernetes to deploy container-based distributed applications. You'll start with an overview of Docker and Kubernetes before building your first Kubernetes cluster. You'll gradually expand your initial application, adding features and deepening your knowledge of Kubernetes architecture and operation. As you navigate this comprehensive guide, you'll explore high-value topics like monitoring, tuning, and scaling.Kubernetes is Greek for \"helmsman,\" your guide through unknown waters. The Kubernetes container orchestration system safely manages the structure and flow of a distributed application, organizing containers and services for maximum efficiency. Kubernetes serves as an operating system for your clusters, eliminating the need to factor the underlying network and server infrastructure into your designs.", "press":"Manning Publications", "publish_date":"2017-08-31" }
下面将演示搜索的功能,搜索的其中一种语法是:
复制代码GET /index名/type名/_search { "query":{ "match":{ "字段Field名称":"用于搜索的关键字" } } }
那么,根据我们之前存储的数据,如果我们要查询summary字段有Orange的数据的话,命令如下:
复制代码GET /douban/book/_search { "query": { "match": { "summary":"Orange" } } }
返回的结果:
转载来源