1.1 初识
Elasticsearch 是一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎,可以说 Lucene 是当今最先进,最高效的全功能开源搜索引擎框架。
但是 Lucene 只是一个框架,要充分利用它的功能,你需要使用 JAVA,并且在你的程序中集成 Lucene。更糟的是,你需要做很多的学习了解,才能明白它是如何运行的,Lucene 确实非常复杂。
Elasticsearch 使用 Lucene 作为内部引擎,但是在你使用它做全文搜索时,只需要使用统一开发好的API即可,而并不需要了解其背后复杂的 Lucene 的运行原理。
当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:
- 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
- 实时分析的分布式搜索引擎。
- 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
这么多的功能被集成到一台服务器上,你可以轻松地通过客户端或者任何你喜欢的程序语言与 ES 的 RESTful API 进行交流。
Elasticsearch 的上手是非常简单的。它附带了很多非常合理的默认值,这让初学者很好地避免一上手就要面对复杂的理论,它安装好了就可以使用了,用很小的学习成本就可以变得很有生产力。
随着学习的深入,你还可以使用 Elasticsearch 更多高级的功能,整个引擎可以很灵活地进行配置。你可以根据自身需求来定制属于你自己的 Elasticsearch。
1.2 安装
安装 JAVA
yum install java-1.7.0-openjdk -y
安装 Elasticsearch
了解 Elasticsearch 最简单的方法就是去尽情的玩儿它(汗),准备好了我们就开始吧。
安装 Elasticsearch 只有一个要求,就是要安装最新版本的JAVA。你可以到官方网站下载它:www.java.com.
你可以在这里下载到最新版本的 Elasticsearch: elasticsearch.org/download.
curl -L -O http://download.elasticsearch.org/PATH/TO/LATEST/$VERSION.zip
unzip elasticsearch-$VERSION.zip
cd elasticsearch-$VERSION
提示: 当你安装 Elasticsearch 时,你可以到 下载页面 选择Debian或者RP安装包。或者你也可以使用官方提供的 Puppet module 或者 Chef cookbook.
安装 Marvel
这是个付费的监控插件 暂时先不翻译
Marvel is a management and monitoring tool for Elasticsearch which is free for development use. It comes with an interactive console called Sense which makes it very easy to talk to Elasticsearch directly from your browser.
Many of the code examples in this book include a ``View in Sense‘‘ link. When clicked, it will open up a working example of the code in the Sense console. You do not have to install Marvel, but it will make this book much more interactive by allowing you to experiment with the code samples on your local Elasticsearch cluster.
Marvel is available as a plugin. To download and install it, run this command in the Elasticsearch directory:
./bin/plugin -i elasticsearch/marvel/latest
You probably don‘t want Marvel to monitor your local cluster, so you can disable data collection with this command:
echo ‘marvel.agent.enabled: false‘ >> ./config/elasticsearch.yml
运行 Elasticsearch
Elasticsearch 已经蓄势待发,现在你便可以运行它了:
./bin/elasticsearch
如果你想让它在后台保持运行的话可以在命令后面再加一个 -d
开启后你就可以使用另一个终端窗口来进行测试了:
curl ‘http://localhost:9200/?pretty‘
你应该看到如下提示:
{
"status": 200,
"name": "Shrunken Bones",
"version": {
"number": "1.4.0",
"lucene_version": "4.10"
},
"tagline": "You Know, for Search"
}
这就说明你的 Elasticsearch 集群 已经上线运行了,这时我们就可以进行各种实验了。
集群和节点
节点 是 Elasticsearch 运行的实例。集群 是一组有着同样cluster.name
的节点,它们协同工作,互相分享数据,提供了故障转移和扩展的功能。当然一个节点也可以是一个集群。
1.3 API
与 Elasticsearch 通信
如何与 Elasticsearch 通信要取决于你是否使用 JAVA。
Java API
如果你使用的是 JAVA,Elasticsearch 内置了两个客户端,你可以在你的代码中使用:
节点客户端: 节点客户端以一个 无数据节点 的身份加入了一个集群。换句话说,它自身是没有任何数据的,但是他知道什么数据在集群中的哪一个节点上,然后就可以请求转发到正确的节点上并进行连接。
传输客户端: 更加轻量的传输客户端可以被用来向远程集群发送请求。他并不加入集群本身,而是把请求转发到集群中的节点。
这两个客户端都使用 Elasticsearch 的 传输 协议,通过9300端口与 java 客户端进行通信。集群中的各个节点也是通过9300端口进行通信。如果这个端口被禁止了,那么你的节点们将不能组成一个集群。
TIP
Java 的客户端的版本号必须要与 Elasticsearch 节点所用的版本号一样,不然他们之间可能无法识别。
更多关于 Java API 的说明可以在这里找到 Guide.
通过 HTTP 向 RESTful API 传送 json
其他的语言可以通过9200端口与 Elasticsearch 的 RESTful API 进行通信。事实上,如你所见,你甚至可以使用行命令 curl
来与 Elasticsearch 通信。
Elasticsearch 官方提供了很多种编程语言的客户端,也有和许多社区化软件的集成插件,这些都可以在Guide 里面找到。
向 Elasticsearch 发出的请求和其他所有的 HTTP 请求的组成部分是一致的。例如,计算集群中文件的数量,我们就可以使用:
<1> <2> <3> <4>
curl -XGET ‘http://localhost:9200/_count?pretty‘ -d ‘
{ <5>
"query": {
"match_all": {}
}
}
‘
-
- 相应的 HTTP 请求方法 或者 变量 :
GET
,POST
,PUT
,HEAD
或者DELETE
。 - 集群中任意一个节点的访问协议、主机名以及端口。
- 请求的路径。
- 任意一个查询后再加上
?pretty
就可以生成 更加美观 的JSON反馈,以增强可读性。 - 一个 JSON 编码的请求主体(如果需要的话)。
- 相应的 HTTP 请求方法 或者 变量 :
Elasticsearch 将会返回一个 HTTP 状态码类似于 ‘200 OK‘,以及一个 JSON 格式的主体(除了单纯的 ‘HEAD‘ 请求),上面的请求会得到下方的 JSON 主体:
{
"count" : 0,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
}
}
在反馈中,我们并没有看见 HTTP 的头部信息,因为我们没有告知 curl
显示这些内容。如果你想看到头部信息,可以在使用 curl
命令的时候再加上 -i
这个参数:
curl -i -XGET ‘localhost:9200/‘
从现在开始,本书里所有涉及 curl
命令的部分我们都会进行简写,因为主机、端口等信息都是相同的,缩减前的样子:
curl -XGET ‘localhost:9200/_count?pretty‘ -d ‘
{
"query": {
"match_all": {}
}
}‘
我们将会简写成这样:
GET /_count
{
"query": {
"match_all": {}
}
}
1.4 文档
面向文档
程序中的对象很少是单纯的键值与数值的列表。更多的时候它拥有一个复杂的结构,比如包含了日期、地理位置、对象、数组等。
迟早你会把这些对象存储在数据库中。你会试图将这些丰富而又庞大的数据都放到一个由行与列组成的关系数据库中,然后你不得不根据每个字段的格式来调整数据,然后每次重建它你都要检索一遍数据。
Elasticsearch 是 面向文档型数据库,这意味着它存储的是整个对象或者 文档,它不但会存储它们,还会为他们建立索引,这样你就可以搜索他们了。你可以在 Elasticsearch 中索引、搜索、排序和过滤这些文档。不需要成行成列的数据。这将会是完全不同的一种面对数据的思考方式,这也是为什么 Elasticsearch 可以执行复杂的全文搜索的原因。
JSON
Elasticsearch使用 JSON (或称作JavaScript Object Notation ) 作为文档序列化的格式。JSON 已经被大多数语言支持,也成为 NoSQL 领域的一个标准格式。它简单、简洁、易于阅读。
把这个 JSON 想象成一个用户对象:
{
"email": "[email protected]",
"first_name": "John",
"last_name": "Smith",
"about": {
"bio": "Eco-warrior and defender of the weak",
"age": 25,
"interests": [ "dolphins", "whales" ]
},
"join_date": "2014/05/01",
}
虽然 user
这个对象非常复杂,但是它的结构和含义都被保留到 JSON 中了。在 Elasticsearch 中,将对象转换为 JSON 并作为索引要比在表结构中做相同的事情简单多了。
将你的数据转换为 JSON
几乎所有的语言都有将任意数据转换、机构化成 JSON,或者将对象转换为JSON的模块。查看 serialization
以及marshalling
两个 JSON 模块。The official Elasticsearch clients 也可以帮你自动结构化 JSON。
1.5 索引
启程
为了能让你感受一下 Elasticsearch 能做什么以及它是有多么的易用,我们会先为你简单展示一下,其中包括了基本的 创建索引,搜索 以及 聚合。
我们会在这里向你介绍一些新的术语以及简单的概念,即使你没有马上接受这些概念也没有关系。我们会在之后的章节中逐渐帮你理解它们。
所以,准备开始享受 Elasticsearch 的学习之旅把!
建立一个员工名单
想象我们正在为一个名叫 megacorp 的公司的 HR 部门制作一个新的员工名单系统,这些名单应该可以满足实时协同工作,所以它应该可以满足以下要求:
- 数据可以包含多个值的标签、数字以及纯文本内容,
- 可以检索任何职员的所有数据。
- 允许结构化搜索。例如,查找30岁以上的员工。
- 允许简单的全文搜索以及相对复杂的短语搜索。
- 在返回的匹配文档中高亮关键字。
- 拥有数据统计与管理的后台。
为员工档案创建索引
这个项目的第一步就是存储员工的数据。这样你就需要一个“员工档案”的表单,这样每个文档都代表着一个员工。在 Elasticsearch 中,存储数据的行为就叫做 索引(indexing) ,但是在我们索引数据前,我们需要决定将数据存储在哪里。
在 Elasticsearch 中,文档属于一种 类型(type),各种各样的类型存在于一个 索引 中。你也可以通过类比传统的关系数据库得到一些大致的相似之处:
关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns)
Elasticsearch ⇒ 索引 ⇒ 类型 ⇒ 文档 ⇒ 字段(Fields)
一个 Elasticsearch 集群可以包含多个 索引(数据库),也就是说其中包含了很多 类型(表)。这些类型中包含了很多的 文档(行),然后每个文档中又包含了很多的 字段(列)。
索引 索引 索引
你可能发现在 Elasticsearch 中,索引这个词汇已经被赋予了太多意义,所以在这里我们有必要澄清一下:
索引 (名词)
如上文所说,一个 索引 就类似于传统关系型数据库中的 数据库。这里就是存储相关文档的的地方。
索引 (动词)
为一个文档创建索引 是把一个文档存储到一个索引(名词)中的过程,这样它才能被检索。这个过程非常类似于 SQL 中的 INSERT
命令,如果已经存在文档,新的文档将会覆盖旧的文档。
反向索引
在关系数据库中的某列添加一个 索引,比如多路搜索树(B-Tree)索引,就可以加速数据的取回速度, Elasticsearch 以及 Lucene 使用的是一个叫做 反向索引(inverted index) 的结构来实现相同的功能。
通常,每个文档中的字段都被创建了索引(拥有一个反向索引),因此他们可以被搜索。如果一个字段缺失了反向索引的话,它将不能被搜索。我们将会在之后的《反向索引》章节中详细介绍它。
所以为了创建员工名单,我们需要进行如下操作:
- 为每一个员工的 文档 创建索引,每个 文档 都包含了一个员工的所有信息。
- 每个文档都会被标记为
employee
类型。 - 这种类型将存活在
megacorp
这个 索引 中。 - 这个索引将会存储在 Elasticsearch 的集群中
在实际的操作中,这些操作是非常简单的(即使看起来有这么多步骤)。我们可以把如此之多的操作通过一个命令来完成:
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
注意在 /megacorp/employee/1
路径下,包含了三个部分:
名字 | 内容 |
---|---|
megacorp | 索引的名字 |
employee | 类型的名字 |
1 | 当前员工的ID |
请求部分,也就是 JSON 文档,在这里包含了关于这名员工的所有信息。他的名字是 “John Smith”,他已经25岁了,他很喜欢攀岩。
怎么样?很简单吧!我们在操作前不需要进行任何管理操作,比如创建索引,或者为字段指定数据的类型。我们就这么直接地为一个文档创建了索引。Elasticsearch 会在创建的时候为它们设定默认值,所以所有管理操作已经在后台被默默地完成了。
在进行下一步之前,我们再为这个目录添加更多的员工信息吧:
PUT /megacorp/employee/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
PUT /megacorp/employee/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}