Githubhttps://github.com/HealerJean

博客:http://blog.healerjean.com

1、Elasticsearch 应用

1.1、和 Mysql 的对比

  数据库 字段 DDL
mysql Database Table Row Column create table
ES Index 索引 Type 类型 Document 文档 Field 字段 Mapping
  客户端工具 复制方式
mysql navicat, SQLyog, MySQL Workbench 主从
ES elasticsearch-head, Kibana, Elasticsearch-sql, Elasticsearch-HQ 对等

es 在5.x以后,没有了strin g类型,被拆分为关键词搜索 keyword 和全文搜索text

  keyword text
自动分词
支持聚合

1.2、场景

1.2.1、内容搜索

您经营一家网上商店,允许您的客户搜索您销售的产品。在 这种情况下,您可以使用 Elasticsearch 存储整个产品目录 和库存,并为他们提供搜索和搜索词自动补全功能。

1.2.2、日志查询

您希望收集日志或事务数据,并且希望分析这些数据以发现 其中的趋势、统计特性、摘要或反常现象。在这种情况下, 您可以使用Logstash(Elastic Stack的一个组件)来收 集、聚合和分析您的数据,然后使用 Logstash 将经过处理的数据导入Elasticsearch。一旦数据进入 Elasticsearch ,您 就可以通过搜索和聚合来挖掘您感兴趣的任何信息。

1.2.3、内容匹配

您运行一个价格警报平台,它允许为对价格敏感的客户制定 一个规则

例如,“我有兴趣购买特定的电子小工具,如果 小工具的价格在下个月内低于任何供应商的某个价格,我希 望得到通知”。在这种情况下,您可以获取供应商价格,将 其推送到 Elasticsearch,并使用其反向搜索(过滤,也就 是范围查询) 功能根据客户查询匹配价格变动,最终在找到 匹配项后将警报推送给客户。

1.2.4、大量数据存储

您有分析或商业智能需求,并且希望可以对大量数据(数百 万或数十亿条记录)进行快速研究、分析、可视化并提出特定的问题。在这种情况下,您可以使用 Elasticsearch 来存 储数据,然后使用 Kibana( Elastic Stack 的一部分)来构 建自定义仪表盘(dashboard),以可视化对您重要的数据 维度。此外,还可以使用 Elasticsearch 聚合功能对数据执 行复杂的查询。

2、基本概念

2.1、近实时

Elasticsearch 是一个近实时( Near Real TimeNRT )的数据 搜索和分析平台。这意味着从索引文档到可搜索文档都会有一段微小 的延迟(通常是1s以内)。

2.2、集群

集群( cluster )是一个或多个节点( node )的集合,这些节点 将共同拥有完整的数据,并跨节点提供联合索引、搜索和分析功能。 集群由唯一的名称标识( elasticsearch.yml 配置文件中对应参数 cluster.name),集群的名称是elasticsearch.yml 配置文件中最重要的一个配置参数,默认名称为 Elasticsearch,节点只能通过集群 名称加入集群。

注意:

1、请确保不要在不同的环境中使用相同的集群名称,否则可能会导 致节点加入错误的集群。例如,可以使用 loggingdevloggingstageloggingprod 来区分开发、预发布和生产环境的集群。

2、只有一个节点的集群是有效的,而且有特殊的用处,尤其是可以在单节点集群进行快速的开发、测试。此外,可以存在多个独立的集群,每个集群都有自己唯一的集群名称。

2.3、节点

节点( node )是一个 Elasticsearch 的运行实例,也就是一进 程( process),多个节点组成集群,节点存储数据,并参与集群的 索引、搜索和分析功能。

⬤ 与集群一样,节点由一个名称标识,默认情 况下,该名称是在启动时分配给节点的随机通用唯一标识符 (UUID)。如果不希望使用默认值,可以定义所需的任何节点名 称。此名称对于集群管理很重要,因为在实际应用中需要确定网络中 的哪些服务器对应于 Elasticsearch 集群中的哪些节点。

2.3.1、加入集群

可以通过集群名称将节点配置为加入特定集群。

1、默认情况下,每 个节点都被设置为加入一个名为 Elasticsearch的集群,这意味着, 如果在网络上启动了多个节点,并且假设它们可以彼此发现,那么它们都将自动形成并加入一个名为 Elasticsearch的集群。

2、在单个集群中,可以有任意多个节点。此外,如果当前网络上没有其他 Elasticsearch 节点在运行,则默认情况下,启动单个节点将 形成一个名为Elasticsearch 的新单节点集群。

2.3.2、节点实质是一个进程

上面提到了节点实质是一个进程,因此服务器和节点可以 是一对多的关系。还有一点需谨记,无论是开发环境、测试环境还是生产环境请配置有意义的节点名称

2.4、索引

索引( index ) 是具有某种相似特性的文档集合。例如,可以有 存储客户数据的索引,存储产品目录的索引,以及存储订单数据的索 引。索引由一个名称(必须全部是小写)标识,当对其中的文档执行 索引、搜索、更新和删除操作时,该名称指向这个特定的索引。 在单个集群中,可以定义任意多个索引。

2.5、文档

文档( document )是可以被索引的基本信息单元。例如,可以 为单个客户创建一个文档,为单个产品创建另一个文档,以及为单个 订单创建另一个文档。文档以 JSON 表示, JSON是 一种普遍存在的 Internet 数据交换格式。在单个索引中,理论上可以存储任意多的文档。

2.6、分片和副本

索引可能会存储大量数据,这些数据可能会超出单个节点的硬件 限制。例如,占用 1TB 磁盘空间的10 亿个文档的单个索引可能超出单个节点的磁盘容量,或者速度太慢,无法满足搜索请求的性能要求。

2.6.1、分片-解决单个节点容量问题

为了解决这个问题,Elasticsearch 提供了将索引水平切分为多段 ( 称为分片,shard )的能力。创建索引时,只需定义所需的分片 数量。每个分片本身就是一个具有完全功能的独立“索引”,可以分布在集群中的任何节点上。

2.6.1.1、分片很重要,主要有两个原因:

1、分片可以水平拆分数据,实现大数据存储和分析

2、可以跨分片 ( 可能在多个节点上 ) 进行分发和并行操作,从 而提高性能和吞吐量。

如何分配分片以及如何将其文档聚合回搜索请求的机制完全由 Elasticsearch 管理,并且对用户是透明的

2.6.2、副本-防止分片活节点宕机

在随时可能发生故障的网络或云环境中,如果某个分片或节点以 某种方式脱机或因何种原因丢失,则强烈建议用户使用故障转移机制。为此,Elasticsearch 提出了将索引分片复制一个或多个拷贝, 称为副本( replica)。

2.6.2.1、副本很重要,主要有两个原因:

1、副本在分片或节点发生故障时提供高可用性。因此,需要注 意的是,副本永远不会分配到复制它的原始主分片所在的节 点上。也就是分片和对应的副本不可在同一节点上。这很容 易理解,如果副本和分片在同一节点上,当机器发生故障时 会同时丢失,起不到容错的作用

2、通过副本机制,可以提高搜索性能和水平扩展吞吐量,因为 可以在所有副本上并行执行搜索。

总之,每个索引可以分割成多个分片。每个分片可以有零个或多个副本

2.6.3、创建分片和副本

可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,

1、可以随时动态更改副本的数量。

2、 分片的数量理论上不可变更, 唯一的办法重建索引,重新定义分片数量。但还是可以使用 shrinksplit API更改索引的分片数量,但这不是通常的做法,预先评估 准确的分片数量才是最佳方法

默认情况下,Elasticsearch 中的每个索引都分配一个主分片和一个副本,这意味着如果集群中至少有两个节点,则索引将有一个主分片和另一个副本分片(一个完整副本),每个索引总共有两个分片

本质上分片和副本都是一个完整的Lucenes索引,存储的数 据也是完全相同的,都可以称为分片

假设一个索引定义了 3 个分片、2 个副本,那么总共就是 9 个 分片,其中 3 个是主分片,每个主分片有 2 个副本。主分片就 是建立索引时首先建立的分片,或者说当主分片失效时会重 新选出一个副本作为主分片。

1、当索引时,数据会首先到达主分片,然后再把请求分发到其 他副本。

2、当搜索时,主分片和副本都可以接受请求、搜索和分析数据,二者没有区别。

3、安装ES

官网:https://www.elastic.co/cn/downloads/elasticsearch

3.1、安装问题

3.1.1、修改端口

#
http.port: 9200
#

3.1.2、修改权限

Elasticsearch 报错: received plaintext http traffic on an https channel, closing connection …

# Enable security features
xpack.security.enabled: false

xpack.security.enrollment.enabled: true

# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
enabled: false

3.2、启动成功

http://localhost:9200/
{
    "name": "MacPro.mshome.net",
    "cluster_name": "elasticsearch",
    "cluster_uuid": "wm9k6z1cSBGBoV92K7tAFQ",
    "version": {
        "number": "8.2.2",
        "build_flavor": "default",
        "build_type": "tar",
        "build_hash": "9876968ef3c745186b94fdabd4483e01499224ef",
        "build_date": "2022-05-25T15:47:06.259735307Z",
        "build_snapshot": false,
        "lucene_version": "9.1.0",
        "minimum_wire_compatibility_version": "7.17.0",
        "minimum_index_compatibility_version": "7.0.0"
    },
    "tagline": "You Know, for Search"
}

3.3、目录

目录 配置文件 描述
bin   脚本文件,包括启动elasticsearch,安装插件,统计数据等。
config elasticsearch.yml 集群配置文件,user,role based 相关配置等。
JDK   java运行环境
data path.data 数据文件
lib   java类库
logs path.log 日志文件
modules   包含所有es模块
plugins   包含所有以安装的插件

4、安装 kibana

官方:https://www.elastic.co/cn/downloads/kibana

4.1、修改配置 kibana.yml

server.port: 5601


elasticsearch.hosts: ["http://localhost:9200"]

4.2、启动

注意要启动 elasticsearch

./kibana
http://localhost:5601

5、增删改查

5.1、增

5.1.1、创建一个索引

第一个命令使用 PUT 方法创建名为 animal 的索引。在调用的 末尾附加 pretty 命令,就可以打印友好JSON响应。

入参:

PUT /animal?pretty

出参:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "animal"
}

5.1.2、创建单个文档

1、animal 是文档的所在索引,_doc 是类型,1 是我们手工指定 id如果不指定,那就要用 POST 方法,ES 会为我们自动分配

2、

入参

PUT /animal/_doc/1
{
  "name":"熊猫",
  "weight":"500kg",
  "zoo":"北京动物园"
}

出参:

{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

5.1.3、创建多个文档

入参:

PUT /animal/_doc/1
{
  "name":"熊猫100",
  "weight":"500kg",
  "zoo":"北京动物园"
}
PUT /animal/_doc/2
{
  "name":"老虎100",
  "weight":"300kg",
  "zoo":"北京动物园"
}
PUT /animal/_doc/3
{
  "name":"狮子100",
  "weight":"500kg",
  "zoo":"上海动物园"
}
PUT /animal/_doc/4
{
  "name":"孔雀100",
  "weight":"100kg",
  "zoo":"南京动物园"
}
PUT /animal/_doc/5
{
  "name":"鳄鱼100",
  "weight":"400kg",
  "zoo":"河北动物园"
}

出参:

# PUT /animal/_doc/1
{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 4,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 11,
  "_primary_term" : 1
}

# PUT /animal/_doc/2
{
  "_index" : "animal",
  "_id" : "2",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 12,
  "_primary_term" : 1
}

# PUT /animal/_doc/3
{
  "_index" : "animal",
  "_id" : "3",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 13,
  "_primary_term" : 1
}

# PUT /animal/_doc/4
{
  "_index" : "animal",
  "_id" : "4",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 14,
  "_primary_term" : 1
}

# PUT /animal/_doc/5
{
  "_index" : "animal",
  "_id" : "5",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 15,
  "_primary_term" : 1
}

5.2、查

key 说明
_index 文档所属索引名称
_type 文档所属类型名
_id 文档唯一 ID
_score 文档相关性打分
_source 文档 JSON 数据
_version 文档版本信息

5.2.1、根据 Id 查询文档

入参:

GET /animal/_doc/1

出参:

	{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "熊猫",
    "weight" : "500kg",
    "zoo" : "北京动物园"
  }
}

5.2.2、查询全部数据

入参:

GET animal/_search

出参:

{
  "took" : 66,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "animal",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "熊猫100",
          "weight" : "500kg",
          "zoo" : "北京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "老虎100",
          "weight" : "300kg",
          "zoo" : "北京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "狮子100",
          "weight" : "500kg",
          "zoo" : "上海动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "name" : "孔雀100",
          "weight" : "100kg",
          "zoo" : "南京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "name" : "鳄鱼100",
          "weight" : "400kg",
          "zoo" : "河北动物园"
        }
      }
    ]
  }
}

5.2.3、不指定字段查询

查询结果有很多记录,这是因为动物的名字里都带有 100,而我们没有指定字段,下面我们指定字段查询:

入参:

GET animal/_search
{
  "query":{
    "query_string":{
      "query":"100"
    }
  }
}

出参:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 0.09844007,
    "hits" : [
      {
        "_index" : "animal",
        "_id" : "1",
        "_score" : 0.09844007,
        "_source" : {
          "name" : "熊猫100",
          "weight" : "500kg",
          "zoo" : "北京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "2",
        "_score" : 0.09844007,
        "_source" : {
          "name" : "老虎100",
          "weight" : "300kg",
          "zoo" : "北京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "3",
        "_score" : 0.09844007,
        "_source" : {
          "name" : "狮子100",
          "weight" : "500kg",
          "zoo" : "上海动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "4",
        "_score" : 0.09844007,
        "_source" : {
          "name" : "孔雀100",
          "weight" : "100kg",
          "zoo" : "南京动物园"
        }
      },
      {
        "_index" : "animal",
        "_id" : "5",
        "_score" : 0.09844007,
        "_source" : {
          "name" : "鳄鱼100",
          "weight" : "400kg",
          "zoo" : "河北动物园"
        }
      }
    ]
  }
}

5.2.4、指定字段查询

入参:

GET animal/_search
{
  "query":{
    "query_string":{
      "query":"100kg",
      "fields": ["weight"]
    }
  }
}

出参:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.5198257,
    "hits" : [
      {
        "_index" : "animal",
        "_id" : "4",
        "_score" : 1.5198257,
        "_source" : {
          "name" : "孔雀100",
          "weight" : "100kg",
          "zoo" : "南京动物园"
        }
      }
    ]
  }
}

5.3、删

5.3.1、删除文档

入参:

DELETE /animal/_doc/1

出参:

{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 5,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 16,
  "_primary_term" : 1
}

5.4、更

Elasticsearch 提供近实时的数据操作和搜索功能。默认情况 下,从索引、更新、删除数据到在搜索结果中显示数据,会有少于1s 的延迟(刷新间隔)。这是与其他平台(如 SQL )的一个重要区别, 在 SQL 中,数据在事务完成后立即可用

5.4.1、覆盖文档

animal 是文档的所在索引,_doc 是类型,1 是我们手工指定 id如果不指定,那就要用 POST 方法,ES 会为我们自动分配

5.4.1.1、回顾创建单个文档

入参

PUT /animal/_doc/1
{
  "name":"熊猫",
  "weight":"500kg",
  "zoo":"北京动物园"
}

出参:

{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

5.4.1.2、修改文档

ID1。如果用不同的(或相同的)文档再次执行上述命令,那么 Elasticsearch 将在现有文档的基础上替换(即重新索引)一个ID1 的新文档:

入参:

PUT /animal/_doc/1
{
  "name":"熊猫修改",
  "weight":"500kg",
  "zoo":"北京动物园"
}

5.4.2、更新文档 _update

Elasticsearch 除了能够索引和替换文档外,还可以更新文档。

Elasticsearch 实际上并不是进行就地更新,每当进行更新时, Elasticsearch 会删除旧文档,然后索引一个新文档,但这对用户来 说是一次调用。

⬤ 实际上 Elasticsearch 的数据存储结构决定了其不能 像关系数据库那样进行字段级的更新,所有的更新都是先删除旧文 档,再插入一条新文档,但这个过程对用户来说是透明的

5.4.2.1、修改文档

修改 Id1name

注意点:

⬤ 路径 _update

⬤ ` _doc 变成 doc`

POST /animal/_update/1?pretty
{
    "doc": {
        "name": "熊猫update"
    }
}

5.4.2.2、修改文档并新增字段

POST /animal/_update/1?pretty
{
    "doc": {
        "name": "熊猫update",
        "age":10
    }
}

5.5、批量操作 _bulk

除了能够索引、更新和删除单个文档外,Elasticsearch还提供 了使用批量API批量执行上述任何操作的功能。此功能非常重要,因 为它提供了一种非常有效的机制,可以以尽可能少的网络往返时间尽 可能快速地执行多个操作

TODO

5.5.2、注意事项

1、批量API不会由于其中一个操作失败而失败。如果一个操作由于 某个原因失败,它将继续处理后面的其余操作。当批量 API 返回时, 它将为每个操作提供一个状态(以相同的发送顺序),以便用户检查 特定操作是否失败。

2、对于删除操作,并不会立即删除对应的源文档,因为删除只需要 删除文档的 ID。在 Elasticsearch 中,删除操作只是把需要删除的文档的 ID 记录到了一个列表中,当段合并时才有可能真正把源文档删除。

ContactAuthor