Elasticsearch入门
一.Elasticsearch介绍
Elasticsearch 是一个分布式、可扩展、实时的搜索与数据分析引擎。 它能从项目一开始就赋予你的数据以搜索、分析和探索的能力,这是通常没有预料到的。 它存在还因为原始数据如果只是躺在磁盘里面根本就毫无用处。
无论你是需要全文搜索,还是结构化数据的实时统计,或者两者结合,这本指南都能帮助你了解其中最基本的概念, 从最基本的操作开始学习 Elasticsearch。之后,我们还会逐渐开始探索更加高级的搜索技术,不断提升搜索体验来满足你的需求。
二.现有技术栈说明
在大多数应用中,多数实体或对象可以被序列化为包含键值对的 JSON 对象。 一个 键 可以是一个字段或字段的名称,一个 值 可以是一个字符串,一个数字,一个布尔值, 另一个对象,一些数组值,或一些其它特殊类型诸如表示日期的字符串,或代表一个地理位置的对象:
{
"name": "John Smith",
"age": 42,
"confirmed": true,
"join_date": "2014-06-01",
"home": {
"lat": 51.5,
"lon": 0.1
},
"accounts": [
{
"type": "facebook",
"id": "johnsmith"
},
{
"type": "twitter",
"id": "johnsmith"
}
]}
通常情况下,我们使用的术语 对象 和 文档 是可以互相替换的。不过,有一个区别: 一个对象仅仅是类似于 hash 、 hashmap 、字典或者关联数组的 JSON 对象,对象中也可以嵌套其他的对象。 对象可能包含了另外一些对象。在 Elasticsearch 中,术语 文档 有着特定的含义。它是指最顶层或者根对象, 这个根对象被序列化成 JSON 并存储到 Elasticsearch 中,指定了唯一 ID。
三.我们的架构方案分析
一个文档不仅仅包含它的数据 ,也包含 元数据 —— 有关 文档的信息。 三个必须的元数据元素如下:
_index
文档在哪存放
_type
文档表示的对象类别
_id
文档唯一标识
一个 索引 应该是因共同的特性被分组到一起的文档集合。 例如,你可能存储所有的产品在索引 products 中,而存储所有销售的交易到索引 sales 中。 虽然也允许存储不相关的数据到一个索引中,但这通常看作是一个反模式的做法。
实际上,在 Elasticsearch 中,我们的数据是被存储和索引在 分片 中,而一个索引仅仅是逻辑上的命名空间, 这个命名空间由一个或者多个分片组合在一起。 然而,这是一个内部细节,我们的应用程序根本不应该关心分片,对于应用程序而言,只需知道文档位于一个 索引 内。 Elasticsearch 会处理所有的细节。
我们将在 索引管理 介绍如何自行创建和管理索引,但现在我们将让 Elasticsearch 帮我们创建索引。 所有需要我们做的就是选择一个索引名,这个名字必须小写,不能以下划线开头,不能包含逗号。我们用 website 作为索引名举例。
数据可能在索引中只是松散的组合在一起,但是通常明确定义一些数据中的子分区是很有用的。 例如,所有的产品都放在一个索引中,但是你有许多不同的产品类别,比如 "electronics" 、 "kitchen" 和 "lawn-care"。
这些文档共享一种相同的(或非常相似)的模式:他们有一个标题、描述、产品代码和价格。他们只是正好属于“产品”下的一些子类。
Elasticsearch 公开了一个称为 types (类型)的特性,它允许您在索引中对数据进行逻辑分区。不同 types 的文档可能有不同的字段,但最好能够非常相似。 我们将在 类型和映射 中更多的讨论关于 types 的一些应用和限制。
一个 _type
命名可以是大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号, 并且长度限制为256个字符. 我们使用 blog 作为类型名举例。
ID 是一个字符串,当它和 _index 以及 _type 组合就可以唯一确定 Elasticsearch 中的一个文档。 当你创建一个新的文档,要么提供自己的 _id ,要么让 Elasticsearch 帮你生成。
四.索引文档
通过使用 index
API ,文档可以被 索引 —— 存储和使文档可被搜索。 但是首先,我们要确定文档的位置。正如我们刚刚讨论的,一个文档的 _index
、 _type
和 _id
唯一标识一个文档。 我们可以提供自定义的 _id
值,或者让 index
API 自动生成。
如果你的文档有一个自然的标识符 (例如,一个 user_account
字段或其他标识文档的值),你应该使用如下方式的 index
API 并提供你自己 _id
:
PUT /{index}/{type}/{id}{
"field": "value",
...}
举个例子,如果我们的索引称为 website
,类型称为 blog
,并且选择 123
作为 ID ,那么索引请求应该是下面这样:
PUT /website/blog/123{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"}
Elasticsearch 响应体如下所示:
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"created": true}
该响应表明文档已经成功创建,该索引包括 _index
、 _type
和 _id
元数据, 以及一个新元素: _version
。
在 Elasticsearch 中每个文档都有一个版本号。当每次对文档进行修改时(包括删除), _version
的值会递增。 在 处理冲突 中,我们讨论了怎样使用 _version
号码确保你的应用程序中的一部分修改不会覆盖另一部分所做的修改。
如果你的数据没有自然的 ID, Elasticsearch 可以帮我们自动生成 ID 。 请求的结构调整为: 不再使用 PUT 谓词(“使用这个 URL 存储这个文档”), 而是使用 POST 谓词(“存储文档在这个 URL 命名空间下”)。
现在该 URL 只需包含 _index
和 _type
:
POST /website/blog/{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"}
除了 _id
是 Elasticsearch 自动生成的,响应的其他部分和前面的类似:
{
"_index": "website",
"_type": "blog",
"_id": "AVFgSgVHUP18jI2wRx0w",
"_version": 1,
"created": true}
自动生成的 ID 是 URL-safe、 基于 Base64 编码且长度为20个字符的 GUID 字符串。 这些 GUID 字符串由可修改的 FlakeID 模式生成,这种模式允许多个节点并行生成唯一 ID ,且互相之间的冲突概率几乎为零。
为了从 Elasticsearch 中检索出文档,我们仍然使用相同的 _index
, _type
, 和 _id
,但是 HTTP 谓词更改为 GET
:
GET /website/blog/123?pretty
响应体包括目前已经熟悉了的元数据元素,再加上 _source
字段,这个字段包含我们索引数据时发送给 Elasticsearch 的原始 JSON 文档:
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}}
在请求的查询串参数中加上 pretty
参数,正如前面的例子中看到的,这将会调用 Elasticsearch 的 pretty-print 功能,该功能 使得 JSON 响应体更加可读。但是, _source
字段不能被格式化打印出来。相反,我们得到的 _source
字段中的 JSON 串,刚好是和我们传给它的一样。
GET
请求的响应体包括 {"found": true}
,这证实了文档已经被找到。 如果我们请求一个不存在的文档,我们仍旧会得到一个 JSON 响应体,但是 found
将会是 false
。 此外, HTTP 响应码将会是 404 Not Found
,而不是 200 OK
。
我们可以通过传递 -i
参数给 curl
命令,该参数能够显示响应的头部:
curl -i -XGET http://localhost:9200/website/blog/124?pretty
显示响应头部的响应体现在类似这样:
HTTP/1.1 404 Not FoundContent-Type: application/json; charset=UTF-8Content-Length: 83{
"_index" : "website",
"_type" : "blog",
"_id" : "124",
"found" : false}
默认情况下, GET
请求会返回整个文档,这个文档正如存储在 _source
字段中的一样。但是也许你只对其中的 title
字段感兴趣。单个字段能用 _source
参数请求得到,多个字段也能使用逗号分隔的列表来指定。
GET /website/blog/123?_source=title,text
该 _source
字段现在包含的只是我们请求的那些字段,并且已经将 date
字段过滤掉了。
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry" ,
"text": "Just trying this out..."
}}
或者,如果你只想得到 _source
字段,不需要任何元数据,你能使用 _source
端点:
GET /website/blog/123/_source
那么返回的的内容如下所示:
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"}
如果只想检查一个文档是否存在--根本不想关心内容—那么用 HEAD
方法来代替 GET
方法。 HEAD
请求没有返回体,只返回一个 HTTP 请求报头:
curl -i -XHEAD http://localhost:9200/website/blog/123
如果文档存在, Elasticsearch 将返回一个 200 ok
的状态码:
HTTP/1.1 200 OKContent-Type: text/plain; charset=UTF-8Content-Length: 0
若文档不存在, Elasticsearch 将返回一个 404 Not Found
的状态码:
curl -i -XHEAD http://localhost:9200/website/blog/124
HTTP/1.1 404 Not FoundContent-Type: text/plain; charset=UTF-8Content-Length: 0
当然,一个文档仅仅是在检查的时候不存在,并不意味着一毫秒之后它也不存在:也许同时正好另一个进程就创建了该文档。
在 Elasticsearch 中文档是 不可改变 的,不能修改它们。相反,如果想要更新现有的文档,需要 重建索引 或者进行替换, 我们可以使用相同的 index
API 进行实现,在 索引文档 中已经进行了讨论。
PUT /website/blog/123{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"}
在响应体中,我们能看到 Elasticsearch 已经增加了 _version
字段值:
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"created": false }
|
在内部,Elasticsearch 已将旧文档标记为已删除,并增加一个全新的文档。 尽管你不能再对旧版本的文档进行访问,但它并不会立即消失。当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档。
从旧文档构建 JSON
更改该 JSON
删除旧文档
索引一个新文档
唯一的区别在于, update
API 仅仅通过一个客户端请求来实现这些步骤,而不需要单独的 get
和 index
请求。
如若大家觉得感兴趣,请关注我的公众号,后续文章都会在公众号首发
关注我们吧