ElasticSearch概念
ElasticSearch是一个实时分布式搜索和分析引擎,能够让你以前所未有的速度处理大数据成为可能。
它用于全文搜索、结构化搜索、分析以及将三者混用。并且可以在单机以及集群上运行。ES将三个功能整合成为一个一体化的、实时的应用,其对新用户的门槛很低。
为什么要用
大部分数据库在提取可用知识方面显得异常无能。尽管它们能够通过时间戳或者精确匹配做过滤。
- 但是它们能够进行全文搜索,处理同义词和根据相关性给文档打分吗?
- 它们能根据同一份数据生成分析和聚合的结果吗?
- 它们在没有大量工作进程(线程)的情况下能做到对数据的实时处理吗?
概念
ElasticSearch是一个基于Apache Lucene的开源搜索引擎,Apache Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是Lucene只是一个库,如果想要使用,则必须使用Java作为开发语言进行集成,而且Lucene非常复杂,需要深入了解检索的相关知识理解它是如何工作的。
ElasticSearch使用Java开发,并使用Lucene作为核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
ElasticSearch还可以这样描述:
- 分布式的实时文件存储,每个字段都被索引并可被搜索。
- 分布式的实时分析搜索引擎。
- 可以扩展到上百台服务器,处理PB级结构化或非结构化数据。
面向文档
应用中的对象很少只是简单的键值列表,例如MySQL数据库那样,更多的时候它拥有复杂的数据结构,例如包含日期、地理位置、另一个对象或数组。而数据库是行列组成的表格,如果要将一个对象存储到MySQL当中,则就像是将一个丰富、信息表现力强的对象拆散了放入一个非常大的表格中。你不得不拆散对象以适应表模式(一列对应一个字段),然后在查询时再进行重建
Elasticsearch是面向文档的,意味着它可以存储整个对象或文档,然而它不仅仅时存储,还会索引每个文档的内容使之可以被搜索。再Elasticsearch中,你可以对文档(并非表结构)进行索引、搜索、排序、过滤。这种理解数据的方式与MySQL完全不同,也是Elasticsearch能够进行复杂的全文搜索的原因之一。
Elasticsearch使用JSON作为文档序列化格式。
集群和节点
节点node是一个运行着地Elasticsearch实例,集群cluster是一组具有相同cluster.name
的节点集合,他们协同工作,共享数据并提供故障转移和扩展功能。
修改cluster.name
可以通过修改config/
目录下的elasticsearch.yml
文件,然后重启Elasticsearch来实现。
与Elasticsearch交互
JavaAPI
Elasticsearch为Java用户提供了两种内置客户端
节点客户端
节点客户端以无数据节点身份加入集群,即自身不存储任何数据,但是它自导数据在集群中的具体位置,并且能够直接转发请求到对应的节点上。
传输客户端
这个更轻量的传输客户端能够发送请求到远端集群,它自己不加入集群,只是简单转发请求给集群中的节点。Java客户端都使用9300端口与集群交互,使用Elasticsearch传输协议(Elasticsearch transport protocol)。
HTTP
基于HTTP,以JSON为数据交互格式的Restful API。向Elastic发出的请求的组成部分与其他普通的HTTP请求是一样的。
1 | curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>' |
- VERB HTTP方法:get、post、put、head、delete
- PROTOCOL:http或者https(当Elasticsearch前有https代理时可用)
- HOST: Elasticsearch集群中的任何一个节点的主机名,如果是在本地的节点,那么就叫localhost
- PORT: Elasticsearch HTTP服务所在的端口,默认为9200
- PATH: API路径,PATH中可以包含多个组件,例如_cluster/stats
- QUERY_STRING:一些可选的查询请求参数,
?pretty
可以使得请求返回更加美观易读的JSON数据 - BODY:一个JSON格式的请求主体
一个完整的请求:
1 | curl -XGET “localhost:9200/_count?pretty” -d ' |
异常
1 | {"error":"Content-Type header [application/x-www-form-urlencoded] is not supported |
则修改为:
1 | curl -H "Content-Type: application/json" -XGET "localhost:9200/_count?pretty" -d ' |
异常2
1 | { |
垃圾windows命令行导致的,这边建议使用Ubuntu的WSL
一个put的示例
1 | curl |
安装
elasticsearch安装后解压到相应目录即可
启动
进入bin目录后:elasticsearch-service start
关闭服务:elasticsearch-service stop
如果是第一次启动则需要:elasticsearch-service install
插件
安装插件Marvel,Marvel是Elasticsearch的管理和监控工具,包含一个sense的交互控制台,使用户方便地通过浏览器直接于Elasticsearch进行交互。
./bin/elasticsearch-plugin install elasticsearch/marvel/latest
禁用监控,通过命令关闭Marvel:echo 'marvel.agent.enabled: false' >> ./config/elasticsearch.yml
Start
索引
在Elasticsearch中索引具有不同的涵义
- 索引(名词):一个索引就像时传统关系数据库中的数据库,它时相关文档存储的地方
- 索引(动词):索引一个文档,表示把一个文档存储到索引(名词n)中。以便它可以被检索或者查询,很像SQL的
insert
,但差别是如果文档已经存在,新的文档将覆盖旧的文档 - 倒排索引:传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。而Elasticsearch和Lucene使用倒排索引的数据结构达到目的。
默认情况下,文档中的所有字段都会被索引(拥有一个倒排索引),只有这样他们才是可被搜索的。
实例
需求
让我们建立一个员工目录。假设我们刚好在Megacorp工作,这时人力资源部门出于某种目的需要让我们创建一个员工目录,这个目录用于促进人文关怀和用于实时协同工作,所以它有以下不同的需求:
- 数据能够包含多个值的标签、数字和纯文本。
- 检索任何员工的所有信息。
- 支持结构化搜索,例如查找30岁以上的员工。
- 支持简单的全文搜索和更复杂的短语(phrase)搜索
- 高亮搜索结果中的关键字。
- 能够利用图表管理分析这些数据。
索引员工文档
我们首先要做的是存储员工数据,每个文档代表一个员工。在Elasticsearch中存储数据的行为就叫做索引(indexing),不过在索引之前,我们需要明确数据应该存储在哪里。
在Elasticsearch中,文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以画一些简单的对比图来类比传统关系型数据库:
1 | Relational DB -> Databases -> Tables -> Rows -> Columns |
Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。
所以为了创建员工目录,我们将进行如下操作:
- 为每个员工的文档(document)建立索引,每个文档包含了相应员工的所有信息。
- 每个文档的类型为employee。
- employee类型归属于索引megacorp。
- megacorp索引存储在Elasticsearch集群中。
1 | curl -XPUT 'localhost:9200/megacorp/employee/1{ |
搜索
做简单搜索,即只需要执行HTTP GET请求并指出文档的”地址”——索引、类型和ID即可。
简单搜索
搜索单个:
curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/1?pretty"
响应的数据为,数据存在于_source
字段中:
1 | { |
搜索全部员工
curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty"
使用_search
代替原来的文档ID,默认下会返回前10个结果,响应内容的hits
数组会包含我们的文档。
1 | { |
query string
搜索first_name
包含”Smith”的员工,我们将在命令行中使用轻量级的搜索方法,这种方法被称为查询字符串(query string)搜索,因为像我们传递URL参数一样去传递查询语句。
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?q=first_name:Jo&pretty" |
- 查询字符串搜索便于通过命令行完成特定(ad hoc)的搜索
- 但查询字符串搜索存在局限性
DSL
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询,允许你构建更加复杂、强大的查询。
DSL以JSON请求体的形式出现,可以这样表示之前对first_name
的查询
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty" -d' |
更复杂的搜索
让搜索更为复杂一些,依旧想要找到姓氏为“John”的员工,但是我们只想得到年龄大于30岁的员工,即为语句添加过滤器,使得我们高效率地执行员工结构化的搜索
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty" -d' |
gt:greater than。
全文搜索
检索所有喜欢"rock climbing"
的员工
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty" -d' |
默认情况下,Elasticsearch根据结果相关性评分来对结果集进行排序,即文档与查询条件的匹配程序。而在上述搜索中,如果about中只是出现了rock也会出现在结果集合当中。
因此,该全文搜索不仅仅是匹配或不匹配,而且还有着相关性
短语搜索
不仅可以在字段中搜索单独的一个词,还可以匹配若干个词或者短语,例如想要查询同时包含rock
和climbing
(并且是相邻的)的记录。使用match_parse
即可
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty" -d' |
高亮搜索
在语句中增加hightlight
参数,将会高亮匹配到的关键字。
1 | curl -H "Content-Type: application/json" -XGET "http://localhost:9200/megacorp/employee/_search?pretty" -d' |
在返回语句中会增加一个新的部分highlight
,内部会包含来自about字段中的文本,并且用<em>和</em>来标识匹配到的单词
1 | { |