ElasticSearch快速入门
1、Elasticsearch介绍
Elasticsearch是一个开源的分布式、RESTful 风格的搜索和数据分析引擎,它的底层是开源库Apache Lucene。
Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库——无论是开源还是私有,但它也仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理,因为Lucene 非常复杂。
为了解决Lucene使用时的繁复性,于是Elasticsearch便应运而生。它使用 Java 编写,内部采用 Lucene 做索引与搜索,但是它的目标是使全文检索变得更简单,简单来说,就是对Lucene 做了一层封装,它提供了一套简单一致的 RESTful API 来帮助我们实现存储和检索。
当然,Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确地形容:
- 一个分布式的实时文档存储,每个字段可以被索引与搜索;
- 一个分布式实时分析搜索引擎;
- 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据。
2、安装并运行
2.1 安装ElasticSearch
官网:https://www.elastic.co/cn/
下载中心:https://elasticsearch.cn/download/
ElasticSearch我们可以在官网上下载,也可以从上面提供下载中心下载(推荐),在下载 中心中有各个版本,可以根据需求下载对应系统版本即可。此外我们需要准备ElasticSearch运行所需要的环境,Java1.8版本或以上版本,并配置JAVA_HOME环境变量。
下载完成后,将其解压到自己想放置的目录中,在文件中找到bin目录下的elasticsearch.bat文件,双击运行。在弹出的窗口中最后一行输出 started字样。如果启动不成功,我们可以下载低版本试一试。
之后在浏览器中访问地址:http://127.0.0.1:9200/
,在页面返回一串JSON格式的代码,在代码中有显示版本等信息,说明我们的ElasticSearch已经成功跑起来了。
{
"name" : "C14482",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "o7K4FdSpQsWrEB7mQF0Ltw",
"version" : {
"number" : "7.12.0",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "78722783c38caa25a70982b5b042074cde5d3b3a",
"build_date" : "2021-03-18T06:17:15.410153305Z",
"build_snapshot" : false,
"lucene_version" : "8.8.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
2.2 安装Kibana
Kibana这是一个官方推出的把 Elasticsearch 数据可视化的工具,我们可以到官网或者上文提供的下载中心下载(推荐)。下载完成后,我们可以把其放到我们想放置的文件夹中,解压后找到bin目录下的kibana.bat
文件,双击运行,稍等片刻后,在弹出的窗口中看到最后一行输出 http server running at http://localhost:5601
,表示我们启动成功,打开浏览器访问地址http://localhost:5601/app/dev_tools#/console
,能够成访问说明我们的kibana安装完毕。
如果启动失败,可以降低版本或者修改config目录下的kibana.yml
文件试试。
# 将默认配置改成如下:
server.port: 5601
server.host: "0.0.0.0"
# 修改成自己集群的端口号
elasticsearch.url: "http://127.0.0.1:9200"
kibana.index: ".kibana"
3、Elasticsearch基本概念
3.1 全文搜索(Full-text Search)
全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。
在全文搜索的世界中,存在着几个庞大的帝国,也就是主流工具,主要有:
- Apache Lucene
- Elasticsearch
- Solr
- Ferret
3.2 倒排索引(Inverted Index)
该索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。Elasticsearch能够实现快速、高效的搜索功能,正是基于倒排索引原理。
3.3 节点 & 集群(Node & Cluster)
Elasticsearch 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个Elasticsearch实例。单个Elasticsearch实例称为一个节点(Node),一组节点构成一个集群(Cluster)。
3.4 索引(Index)
Elasticsearch 数据管理的顶层单位就叫做 Index(索引),相当于关系型数据库里的数据库的概念。另外,每个Index的名字必须是小写。
3.5 类型(Type)
Document 可以分组,比如employee这个 Index 里面,可以按部门分组,也可以按职级分组。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document,类似关系型数据库中的数据表。
不同的 Type 应该有相似的结构(Schema),性质完全不同的数据(比如 products 和 logs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。
3.6文档(Document)
Index里面单条的记录称为 Document(文档),类似于关系数据库中数据表的一行数据。许多条 Document 构成了一个 Index。Document 使用 JSON 格式表示。同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
3.7 文档元数据(Document metadata)
文档元数据为_index, _type, _id, 这三者可以唯一表示一个文档,_index表示文档在哪存放,_type表示文档的对象类别,_id为文档的唯一标识。
3.8 字段(Fields)
每个Document都类似一个JSON结构,它包含了许多字段,每个字段都有其对应的值,多个字段组成了一个 Document,可以类比关系型数据库数据表中的字段。
在 Elasticsearch 中,文档(Document)归属于一种类型(Type),而这些类型存在于索引(Index)中,下图展示了Elasticsearch与传统关系型数据库的类比:
4、ElasticSearch入门
Elasticsearch提供了多种交互使用方式,包括Java API和RESTful API ,本文主要介绍RESTful API 。所有其他语言可以使用RESTful API 通过端口 9200 和 Elasticsearch 进行通信,你可以用你最喜爱的 web 客户端访问 Elasticsearch 。甚至,你还可以使用 curl
命令来和 Elasticsearch 交互。
一个Elasticsearch请求和任何 HTTP 请求一样,都由若干相同的部件组成:
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
返回的数据格式为JSON,因为Elasticsearch中的文档以JSON格式储存。其中,被 < >
标记的部件:
部件 | 说明 |
---|---|
VERB | 适当的 HTTP 方法 或 谓词 : GET 、 POST 、 PUT 、 HEAD 或者 DELETE 。 |
PROTOCOL | http 或者 https (如果你在 Elasticsearch 前面有一个 https 代理) |
HOST | Elasticsearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点。 |
PORT | 运行 Elasticsearch HTTP 服务的端口号,默认是 9200 。 |
PATH | API 的终端路径(例如 _count 将返回集群中文档数量)。Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm 。 |
QUERY_STRING | 任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读) |
BODY | 一个 JSON 格式的请求体 (如果请求需要的话) |
对于HTTP方法,它们的具体作用为:
HTTP方法 | 说明 |
---|---|
GET | 获取请求对象的当前状态 |
POST | 改变对象的当前状态 |
PUT | 创建一个对象 |
DELETE | 销毁对象 |
HEAD | 请求获取对象的基础信息 |
接下来我们就开始通过实际操作来学习ElasticSearch,以下操作均在Kibana中完成,通过浏览器访问地址:http://localhost:5601/app/dev_tools#/console
。
4.1 创建索引
在ElasticSearch索引中,对应于CRUD中的“创建”和“更新”。如果对具有给定类型的文档进行索引,并且要插入原先不存在的ID。 如果具有相同类型和ID的文档已存在,则会被覆盖。
要索引第一个JSON对象,我们对REST API创建一个PUT请求到一个由索引名称,类型名称和ID组成的URL。 也就是:http://localhost:9200/<index>/<type>/[<id>]
。
索引和类型是必需的,而ID
部分是可选的。如果不指定ID
,ElasticSearch会为我们生成一个ID
。 但是,如果不指定ID,应该使用HTTP的POST
而不是PUT
请求。
索引名称是任意的。如果服务器上没有此名称的索引,则将使用默认配置来创建一个索引。
至于类型名称,它也是任意的。 它有几个用途,包括:
- 每种类型都有自己的ID空间。
- 不同类型具有不同的映射(“模式”,定义属性/字段应如何编制索引)。
- 搜索多种类型是可以的,并且也很常见,但很容易搜索一种或多种指定类型。
现在我们来索引一些内容! 可以把任何东西放到索引中,只要它可以表示为单个JSON对象。在本教程中,使用索引和搜索电影的一个示例。这是一个经典的电影对象信息:
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972
}
要创建一个索引,这里使用索引的名称为“movies”,类型名称(“movie”)和id(“1”),并按照上述模式使用JSON对象在正文中进行请求。
curl -XPUT "http://localhost:9200/movies/movie/1" -d'
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972
}'
可以使用curl来执行它,也可以使用Sense。这里使用Sense,可以自己填充URL,方法和请求正文,或者您以复制上述curl示例,将光标置于Sense中的正文字段中写入上面的Json对象,然后按点击绿色小箭头来执行创建索引操作。如下图所示:
执行请求后,可以看到接收到来自ElasticSearch响应的JSON对象。
{
"_index" : "movies",
"_type" : "movie",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
4.2 更新索引
现在,在索引中有了一部电影信息,接下来来了解如何更新它,添加一个类型列表。要做到这一点,只需使用相同的ID索引它。使用与之前完全相同的索引请求,但类型扩展了JSON对象。
curl -XPUT "http://localhost:9200/movies/movie/1" -d'
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972,
"genres": ["Crime", "Drama"]
}'
JSON
ElasticSearch的响应结果与前面的大体上一样,但有一点区别,结果对象中的_version
属性的值为2
,而不是1
。响应结果如下:
{
"_index" : "movies",
"_type" : "movie",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
版本号(_version
)可用于跟踪文档已编入索引的次数。它的主要目的是允许乐观的并发控制,因为可以在索引请求中提供一个版本,如果提供的版本高于索引中的版本,ElasticSearch将只覆盖文档内容,ID值不变,版本号自动添加。
4.3 由ID获取文档/索引
上面已经学习了索引新文档以及更新存在的文档。还看到了一个简单搜索请求的示例。如果只是想检索一个具有已知ID的索引,一个方法是搜索索引中的文档。另一个简单而快速的方法是通过ID
,使用GET
来检索它。
简单的做法是向同一个URL发出一个GET请求,URL的ID部分是强制性的。通过ID从ElasticSearch中检索文档可发出URL的GET请求:http://localhost:9200/<index>/<type>/<id>
。
使用以下请求尝试获取电影信息:
curl -XGET "http://localhost:9200/movies/movie/1" -d''
响应结果如下:
{
"_index" : "movies",
"_type" : "movie",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "The Godfather",
"director" : "Francis Ford Coppola",
"year" : 1972,
"genres" : [
"Crime",
"Drama"
]
}
}
结果对象包含与索引时所看到的类似的元数据,如索引,类型和版本信息。 最后最重要的是,它有一个名称为“_source
”的属性,它包含实际获取的文档信息。
4.4 删除文档
为了通过ID从索引中删除单个指定的文档,使用与获取索引文档相同的URL,只是这里将HTTP方法更改为DELETE
。
curl -XDELETE "http://localhost:9200/movies/movie/1" -d''
响应对象包含元数据方面的一些常见数据字段,以及名为“_found
”的属性,表示文档确实已找到并且操作成功。
{
"_index" : "movies",
"_type" : "movie",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
在执行DELETE
调用后切换回GET
,可以验证文档是否确实已删除。
执行: curl -XGET "http://localhost:9200/movies/movie/1" -d''
响应结果:
{
"_index" : "movies",
"_type" : "movie",
"_id" : "1",
"found" : false
}
4.5 搜索
在前面,已经介绍了在ElasticSearch索引中处理数据的基础知识,现在是时候进行核心功能的学习了。考虑到之前我们删除索引中的所有文档,所以,在进行搜索学习之前,需要一些添加一些示例数据。使用以下这些请求和数据对象来创建索引。
curl -XPUT "http://localhost:9200/movies/movie/1" -d'
{
"title": "The Godfather",
"director": "Francis Ford Coppola",
"year": 1972,
"genres": ["Crime", "Drama"]
}'
curl -XPUT "http://localhost:9200/movies/movie/2" -d'
{
"title": "Lawrence of Arabia",
"director": "David Lean",
"year": 1962,
"genres": ["Adventure", "Biography", "Drama"]
}'
curl -XPUT "http://localhost:9200/movies/movie/3" -d'
{
"title": "To Kill a Mockingbird",
"director": "Robert Mulligan",
"year": 1962,
"genres": ["Crime", "Drama", "Mystery"]
}'
curl -XPUT "http://localhost:9200/movies/movie/4" -d'
{
"title": "Apocalypse Now",
"director": "Francis Ford Coppola",
"year": 1979,
"genres": ["Drama", "War"]
}'
curl -XPUT "http://localhost:9200/movies/movie/5" -d'
{
"title": "Kill Bill: Vol. 1",
"director": "Quentin Tarantino",
"year": 2003,
"genres": ["Action", "Crime", "Thriller"]
}'
curl -XPUT "http://localhost:9200/movies/movie/6" -d'
{
"title": "The Assassination of Jesse James by the Coward Robert Ford",
"director": "Andrew Dominik",
"year": 2007,
"genres": ["Biography", "Crime", "Drama"]
}'
值得指出的是,ElasticSearch具有和端点(_bulk
)用于用单个请求索引多个文档,但是这超出了本教程的范围,这里只保持简单,使用六个单独的请求学习。
4.5.1 _search端点
现在已经把一些电影信息放入了索引,可以通过搜索看看是否可找到它们。 为了使用ElasticSearch进行搜索,我们使用_search
端点,可选择使用索引和类型。也就是说,按照以下模式向URL发出请求:<index>/<type>/_search
。其中,index
和type
都是可选的。
换句话说,为了搜索电影,可以对以下任一URL进行POST请求:
http://localhost:9200/_search
- 搜索所有索引和所有类型。http://localhost:9200/movies/_search
- 在电影索引中搜索所有类型http://localhost:9200/movies/movie/_search
- 在电影索引中显式搜索电影类型的文档。
因为我们只有一个单一的索引和单一的类型,所以怎么使用都不会有什么问题。为了简洁起见使用第一个URL。
4.5.2 搜索请求正文和ElasticSearch查询DSL
如果只是发送一个请求到上面的URL,我们会得到所有的电影信息。为了创建更有用的搜索请求,还需要向请求正文中提供查询。 请求正文是一个JSON对象,除了其它属性以外,它还要包含一个名称为“query
”的属性,这就可使用ElasticSearch的查询DSL。
基本自由文本搜索
查询DSL具有一长列不同类型的查询可以使用。 对于“普通”自由文本搜索,最有可能想使用一个名称为“查询字符串查询”。
查询字符串查询是一个高级查询,有很多不同的选项,ElasticSearch将解析和转换为更简单的查询树。如果忽略了所有的可选参数,并且只需要给它一个字符串用于搜索,它可以很容易使用。
现在尝试在两部电影的标题中搜索有“kill”这个词的电影信息:
curl -XPOST "http://localhost:9200/_search" -d'
{
"query": {
"query_string": {
"query": "kill"
}
}
}'
执行结果:
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 6,
"successful" : 6,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0467482,
"hits" : [
{
"_index" : "movies",
"_type" : "movie",
"_id" : "3",
"_score" : 1.0467482,
"_source" : {
"title" : "To Kill a Mockingbird",
"director" : "Robert Mulligan",
"year" : 1962,
"genres" : [
"Crime",
"Drama",
"Mystery"
]
}
},
{
"_index" : "movies",
"_type" : "movie",
"_id" : "5",
"_score" : 1.0467482,
"_source" : {
"title" : "Kill Bill: Vol. 1",
"director" : "Quentin Tarantino",
"year" : 2003,
"genres" : [
"Action",
"Crime",
"Thriller"
]
}
}
]
}
}
total:value=2
共查询到数据2条。正如预期的,得到两个命中结果,每个电影的标题中都带有“kill”单词。再看看另一种情况,在特定字段中搜索。
4.5.3 指定搜索的字段
在前面的例子中,使用了一个非常简单的查询,一个只有一个属性“query
”的查询字符串查询。 如前所述,查询字符串查询有一些可以指定设置,如果不使用,它将会使用默认的设置值。
这样的设置称为“fields”,可用于指定要搜索的字段列表。如果不使用“fields”字段,ElasticSearch查询将默认自动生成的名为“_all
”的特殊字段,来基于所有文档中的各个字段匹配搜索。
为了做到这一点,修改以前的搜索请求正文,以便查询字符串查询有一个fields
属性用来要搜索的字段数组:
curl -XPOST "http://localhost:9200/_search" -d'
{
"query": {
"query_string": {
"query": "ford",
"fields": ["title"]
}
}
}'
响应结果:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 6,
"successful" : 6,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.9794736,
"hits" : [
{
"_index" : "movies",
"_type" : "movie",
"_id" : "6",
"_score" : 0.9794736,
"_source" : {
"title" : "The Assassination of Jesse James by the Coward Robert Ford",
"director" : "Andrew Dominik",
"year" : 2007,
"genres" : [
"Biography",
"Crime",
"Drama"
]
}
}
]
}
}
hits:total:value=1
如预期的得到一个命中,电影的标题中的单词“ford
”。
原文链接:https://www.yiibai.com/elasticsearch/elasticsearch-getting-start.html