一、Elasticsearch 简介
你可以这么形容 Elasticsearch :
- 一个分布式的实时文档存储,每个字段都可以被索引与搜索
- 一个分布式近实时分析搜索引擎
- 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据
Elasticsearch 是一个实时分布式搜索和分析引擎,建立在一个全文搜索引擎库 Apache Lucene 基础之上,而 Lucene 是当下最先进、高性能、全功能的搜索引擎库。
但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理,因为 Lucene 非常复杂。
Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。
- 维基百科使用 Elasticsearch 提供全文搜索并高亮关键字,以及输入实时搜索(search-asyou-type)和搜索纠错(did-you-mean)等搜索建议功能。
- 英国卫报使用 Elasticsearch 结合用户日志和社交网络数据提供给他们的编辑以实时的反馈,以便及时了解公众对新发表的文章的回应。
- StackOverflow 结合全文搜索与地理位置查询,以及 more-like-this 功能来找到相关的问题和答案。
- Github 使用 Elasticsearch 检索 1300 亿行的代码。
- ...
Elasticsearch 不仅用于大型企业,它还让像 DataDog 以及 Klout 这样的创业公司将最初的想法变成可扩展的解决方案,Elasticsearch 可以在你的笔记本上运行,也可以在数以百计的服务器上处理 PB 级别的数据。
二、Elasticsearch 安装
三、Elasticsearch 基本概念
文档(Document)
JSON 格式,Elasticsearch 存储的最小单位,可以理解为是关系型数据库中的一条记录,每个文档都有自己的一个 unique id。
文档元数据,用于标注文档的相关信息
- _index:文档所属的索引名
- _type:文档所属的类型名
- _source:文档的原始Json数据
- _id:文档唯一id
- _version:文档版本信息
- _score:文档相关度打分
_score 相关度是一个很重要的概念,阐明了 Elasticsearch 在全文属性上搜索并返回相关性最强的结果,这是完全区别于传统关系型数据库的一个概念,数据库中的一条记录要么匹配要么不匹配。
文档(Document)是不可变的:它们不能被修改,只能被替换。因此对于 Document 的所有修改操作,在其内部都要经历检索-修改-重建索引的处理过程。
索引(Index)、类型(Type)
索引(Index)是文档的一个容器,类比于关系型数据库的数据库概念,索引中的 setting 里定义有多少个 shards 来存储索引数据,数据是如何分布。
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
类型(Type)可以理解成关系型数据库中的 Table。
因此 每个索引(Index)包含多个类型(Type),不同的类型存储着多个文档(Document),每个文档又有多个属性(Field)
分片、副本
一个运行中的 Lucene 实例称为一个分片,分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。当你的集群规模扩大或者缩小时,Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。
一个分片可以是主分片或者副本分片。
主分片用于解决水平扩展问题,将索引海量数据分布到集群内所有的节点之上(默认通过 id 的 hash),主分片在索引创建的时候确定,后续不允许修改(除非 Reindex 操作进行修改)。
副本分片是用于解决高可用问题,当主分配出现问题时,副本分片会被集群升级为主分片,副本分片个数的决定了写入性能和读取吞吐量,副本数量越多写入性能越差,但读取吞吐量就会越高,在运行中的集群上是可以动态调整副本分片数目的。
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
如果主分片和副本分片都集中在一个节点上,那是没办法做到高可用的。ES 的集群监控状态会返回 yellow(表示全部主分片都正常运行,副本分片没有全部处在正常状态)。因此,需要启动更多的节点来承载副本分片。
集群、节点
一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成,它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。
Master 节点,负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等,而 Master 节点并不需要涉及到文档级别的变更和搜索等操作。
Data 节点,存储数据节点。
Coordinating (协调)节点,负责接收客户端请求,分发请求到其他节点,最后再将数据汇集响应给客户端。集群中得任何节点都可以作为协调节点,包括主节点,每个节点都知道任意文档所处的位置。
集群中的节点通过端口 9300 彼此通信。如果这个端口没有打开,节点将无法形成一个集群。
四、Elasticsearch 数据和检索
Elasticsearch 是面向文档的,使用 JSON 作为文档的序列化格式,而且 Elasticsearch 不仅存储文档,还索引每个文档的内容,使之可以被检索、排序和过滤,而这也是 Elasticsearch 能支持复杂全文检索的原因。
在 Elasticsearch 中, 每个字段的所有数据都是默认被索引的。即每个字段都有为了快速检索设置的专用倒排索引。而且,不像其他多数的数据库,它能在同一个查询中使用所有这些倒排索引,并以惊人的速度返回结果。
我们可以使用 RESTful API 通过端口 9200(默认)和 Elasticsearch 进行通信,可以使用 kibana 访问 Elasticsearch ,甚至可以直接使用 curl 命令来和 Elasticsearch 交互。
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
VERB:适当的 HTTP 方法或谓词 : GET、POST、PUT、HEAD 或者 DELETE。
PROTOCOL:http 或者 https。
HOST:Elasticsearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点。
PORT:Elasticsearch HTTP 服务的端口号,默认是 9200.
PATH:API 的终端路径(例如 _count 将返回集群中文档数量)。Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm 。
QUERY_STRING:可选,查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读)
BODY:可选,一个 JSON 格式的请求体
更多 DSL 语法可以参考:https://www.elastic.co/guide/en/elasticsearch/reference/7.9/search-search.html
如果你正在使用 Java,在代码中你可以使用 Elasticsearch 内置的两个客户端:
节点客户端(Node client)
节点客户端作为一个非数据节点加入到本地集群中。换句话说,它本身不保存任何数据,但是它知道数据在集群中的哪个节点中,并且可以把请求转发到正确的节点。
传输客户端(Transport client)
轻量级的传输客户端可以将请求发送到远程集群。它本身不加入集群,但是它可以将请求转发到集群中的一个节点上。
两个 Java 客户端都是通过 9300 端口并使用 Elasticsearch 的原生传输协议和集群交互。