zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

Elasticsearch

2023-09-11 14:19:18 时间

上一篇:es安装常见问题
下一篇:Elasticsearch Java REST Client 初始化、添加索引及数据

Elasticsearch是什么?

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
--------来源百度百科

Elasticsearch日常使用场景

Elasticsearch概念(基于6.0)

GitHub地址

官网地址

Near Realtime (NRT)(近实时)

Elasticsearch 是一个近乎实时的搜索平台。这意味着从您为文档编制索引到它变得可搜索之间存在轻微的延迟(通常为一秒)

Cluster(簇、组、集群)

集群是一个或多个节点(服务器)的集合,它们一起保存您的整个数据并提供跨所有节点的联合索引和搜索功能。集群由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为只有将节点设置为按其名称加入集群时,该节点才能成为集群的一部分。

Node (节点)

节点是集群的一部分,存储数据并参与集群的索引和搜索功能的单个服务器。就像集群一样,节点由名称标识,默认情况下,该名称是在启动时分配给节点的随机通用唯一标识符
(UUID)。如果您不想要默认值,您可以定义任何您想要的节点名称。此名称对于您要识别网络中的哪些服务器对应于 Elasticsearch
集群中的哪些节点的管理目的很重要。

可以将节点配置为通过集群名称加入特定集群。默认情况下,每个节点都设置为加入一个elasticsearch名为elasticsearch.

在单个集群中,您可以拥有任意数量的节点。此外,如果您的网络上当前没有运行其他 Elasticsearch
节点,则默认启动单个节点将形成一个名为elasticsearch.

Index (索引)

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

Type (类型)

一种类型曾经是索引的逻辑类别/分区,在6.0.0版本中已弃用

Document (文档)

文档是可以被索引的基本信息单元。例如,您可以为单个客户创建一个文档,为单个产品创建另一个文档,以及为单个订单创建另一个文档。本文档以JSON(JavaScript 对象表示法)表示,这是一种普遍存在的互联网数据交换格式。
在索引/类型中,您可以存储任意数量的文档。请注意,尽管文档物理上驻留在索引中,但文档实际上必须被索引/分配给索引内的类型。

Shards & Replicas (碎片和副本)

索引可能会存储大量数据,这些数据可能超出单个节点的硬件限制。例如,占用 1TB 磁盘空间的十亿个文档的单个索引可能不适合单个节点的磁盘,或者可能太慢而无法单独处理来自单个节点的搜索请求。

为了解决这个问题,Elasticsearch
提供了将您的索引细分为多个称为分片的片段的能力。创建索引时,您可以简单地定义所需的分片数量。每个分片本身就是一个功能齐全且独立的“索引”,可以托管在集群中的任何节点上。

分片之所以重要,主要有两个原因:

   1、它允许您水平拆分/缩放内容量 它允许您跨分片(可能在多个节点上)分布和并行化操作,从而提高性能/吞吐量
   2、分片的分布机制以及其文档如何聚合回搜索请求的机制完全由 Elasticsearch 管理,并且对您作为用户是透明的。

在随时可能出现故障的网络/云环境中,非常有用且强烈建议使用故障转移机制,以防分片/节点因某种原因脱机或消失。为此,Elasticsearch
允许您将索引分片的一个或多个副本制作成所谓的副本分片或简称副本。

复制之所以重要,主要有两个原因:

它在分片/节点失败的情况下提供高可用性。出于这个原因,重要的是要注意,副本分片永远不会与从中复制它的原始/主分片分配在同一节点上。
它允许您扩展搜索量/吞吐量,因为搜索可以在所有副本上并行执行。
总而言之,每个索引都可以拆分为多个分片。索引也可以复制零次(意味着没有副本)或多次。复制后,每个索引将具有主分片(从中复制的原始分片)和副本分片(主分片的副本)。可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,您可以随时动态更改副本数,但不能事后更改分片数。

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


每个 Elasticsearch 分片都是一个 Lucene 索引。在单个 Lucene
索引中可以拥有的文档数量是最大的。截至LUCENE-5843,限制为2,147,483,519(= Integer.MAX_VALUE -
128) 个文档。_cat/shards您可以使用API监控分片大小。

Elasticsearch安装

jdk版本需要java8及以上版本
官方推荐:JDK版本:1.8.0_131
elasticsearch linux安装及集成源码
官网安装文档,含多平台安装方式

官网单节点安装

# 下载tar文件
 curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.1.tar.gz
# 解压
tar -xvf elasticsearch-6.0.1.tar.gz
# 进入elasticsearch解压文件夹下的bin目录
cd elasticsearch-6.0.1/bin
# 运行
./elasticsearch

运行成功之后可使用REST API
1、检查您的集群、节点和索引的运行状况、状态和统计信息
2、管理您的集群、节点和索引数据和元数据
3、对索引执行 CRUD(创建、读取、更新和删除)和搜索操作
4、执行高级搜索操作,例如分页、排序、过滤、脚本、聚合等

可视化工具kibana下载

下载
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.0-linux-x86_64.tar.gz
wget https://artifacts.elastic.co/downloads/kibana/kibana-6.7.0-linux-x86_64.tar.gz
解压
tar -zxvf kibana-7.17.0-linux-x86_64.tar.gz
修改config文件夹下的kibana.yml,将以下注解打开,
如果配置了X-pack,则将对应的注解也打开
server.host:
elasticsearch.hosts:
在bin目录下启动
./kibana
如果出现下列提示,
Kibana should not be run as root. Use --allow-root to continue.
则使用,下面方式启动
./kibana --allow-root

启动报错
Another Kibana instance appears to be migrating the index. Waiting for that migration to complete. If no other Kibana instance is attempting migrations, you can get past this message by deleting index .kibana_1 and restarting Kibana
执行删除,重新启动
curl -XDELETE http://localhost:9200/.kibana_1

访问:localhost:5601
在这里插入图片描述

Cluster Health (集群运行状况)

在这里插入图片描述

# 运行: GET /_cat/health?v
# 结果:
epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1644400769 09:59:29  elasticsearch green           1         1      1   1    0    0        0             0                  -                100.0%

绿色 - 一切都很好(集群功能齐全)
黄色 - 所有数据都可用,但尚未分配一些副本(集群功能齐全)
红色 - 某些数据由于某种原因不可用(集群部分功能)

# 运行:GET /_cat/nodes?v
# 结果:
ip            heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1           28          79   7    0.26    0.38     1.43 mdi       *      8SO9PKW

看到一个名为“8SO9PKW”的节点,它是我们集群中当前的单个节点

Rest API 操作

# 列出所有索引:GET /_cat/indices?v
# 结果:
health status index     uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .kibana_1 9EHnqpeqQ9uWXUq3LQ   1   0          3            0       12kb           12kb

获取到一个索引为:.kibana_1的数据
# 索引名称必须为小写,否则创建失败
# 创建索引:PUT /test-index-demo?pretty
# 说明:创建一个名称为:test-index-demo 的索引,pretty并输出json格式的结果
# 结果:
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "test-index-demo_1"
}
# 再次执行列出所有索引:
health status index             uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   test-index-demo   DxUj1k0ASu6NvyNxChYg   5   1          0            0      1.1kb          1.1kb
yellow open   customer          6SIXNJL4SqKpMHGsLvg    5   1          0            0      1.2kb          1.2kb
green  open   .kibana_1         9EHnqpeqQ9uWGDq3LQ     1   0          3            0       12kb           12kb
yellow open   test-index-demo_1 9EkjGayQR9aOT7SF5w     5   1          0            0      1.1kb          1.1kb

Index and Query a Document(索引和查询文档)

# 在索引中添加数据:
PUT /customer/doc/1?pretty
{
  "name": "小白"
}
# 说明doc 表示一个文档,1表示当前添加的数据内部id为1,如果不指定,es默认指定
# 结果
{
  "_index" : "customer",
  "_type" : "doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}
# 通过id查询数据:GET /customer/doc/1?pretty
# 结果:
{
  "_index" : "customer",
  "_type" : "doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "小白"
  }
}
# found:true   表示查询到了数据,false未查到
# _source  是查询到的结果完整的json文档

当向已存在的id中继续PUT 数据,会修改原来的数据 ,如果PUT的数据不存在则会追加

删除索引

# 执行:DELETE /customer?pretty
# 结果:
 {
      "acknowledged" : true
 }
# 表示数据存在,且删除成功
# 如果不存在,结果如下
{
  "error" : {
    "root_cause" : [
      {
        "type" : "index_not_found_exception",
        "reason" : "no such index",
        "resource.type" : "index_or_alias",
        "resource.id" : "test-index-demo_2",
        "index_uuid" : "_na_",
        "index" : "test-index-demo_2"
      }
    ],
    "type" : "index_not_found_exception",
    "reason" : "no such index",
    "resource.type" : "index_or_alias",
    "resource.id" : "test-index-demo_2",
    "index_uuid" : "_na_",
    "index" : "test-index-demo_2"
  },
  "status" : 404
}
# 删除指定数据:DELETE /customer/doc/2?pretty

修改文档

# 关键字:_update
# 执行:
POST /customer/doc/1/_update?pretty
{
  "doc": { "name": "Jane Doe" }
}
# 说明:修改内部id为1,key为name的数据

批量处理

# 关键字:_bulk
# 执行:
POST /customer/doc/_bulk?pretty
{"index":{"_id":"3"}}
{"name": "娃哈哈" }
{"index":{"_id":"4"}}
{"name": "纯净水" }
# 结果:
{
  "took" : 10,
  "errors" : false,
  "items" : [
    {
      "index" : {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "3",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 2,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "4",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 2,
        "status" : 201
      }
    }
  ]
}

混合操作

# 执行
POST /customer/doc/_bulk?pretty
{"update":{"_id":"1"}}
{"doc": { "name": "大汝州" } }
{"delete":{"_id":"2"}}
# 说明:将id=1的数据中name值修改为 "大汝州",删除id=2的数据
# 结果,如果修改/删除的数据不存在则status=404
{
  "took" : 3,
  "errors" : false,
  "items" : [
    {
      "update" : {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "1",
        "_version" : 3,
        "result" : "noop",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "status" : 200
      }
    },
    {
      "delete" : {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "4",
        "_version" : 2,
        "result" : "deleted",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 2,
        "_primary_term" : 2,
        "status" : 200
      }
    }
  ]
}

搜索

# 关键字:_search
# 执行: GET /customer/_search?q=*&sort=_id:asc&pretty
# 说明:获取索引为customer下的所有数据并且内部id为正序排列,注意排序的字段如果是字符串类型的,需要使用:排序字段.keyword
# 例如:GET /customer/_search?q=*&sort=name.keyword:asc&pretty
# 执行结果: 
{
  "took" : 12,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "天方方便面",
          "age" : 26,
          "birthday" : "2022-01-01"
        },
        "sort" : [
          "1"
        ]
      },
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "qKIc3n4BeDUfn7IZFYOH",
        "_score" : null,
        "_source" : {
          "name" : "小白象啊",
          "age" : 26,
          "birthday" : "2022-01-01"
        },
        "sort" : [
          "qKIc3n4BeDUfn7IZFYOH"
        ]
      }
    ]
  }
}
# 结果说明:
took– Elasticsearch 执行搜索的时间(以毫秒为单位)
timed_out– 告诉我们搜索是否超时
_shards– 告诉我们搜索了多少分片,以及搜索成功/失败的分片计数
hits- 搜索结果
hits.total– 符合我们搜索条件的文档总数
hits.hits– 实际的搜索结果数组(默认为前 10 个文档)
hits.sort- 结果的排序键(如果按分数排序则缺失)
hits._score和max_score- 暂时忽略这些字段
# 上边搜索方式的另一种实现
# 说明:这query部分告诉我们查询定义是什么,而这match_all部分只是我们想要运行的查询类型。match_all查询只是搜索指定索引中的所有文档。
# 执行:
GET /customer/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "birthday": "asc" }
  ]
}
# 结果与上边的搜索一致,
# size:查询1条数的数据,默认是10条数据
# 执行:
GET /customer/_search
{
  "query": { "match_all": {} },
  "size": 1
}
# 执行:
GET /customer/_search
{
  "query": { "match_all": {} },
  "from": 0,
  "size": 10
}
# from是从第几条开始,默认是从0开始,0是第一条数据
# size 是想要返回的结果条数

# 执行:
GET /customer/_search
{
  "query": { "match_all": {} },
  "sort": { "age": { "order": "asc" } }
}
# 说明: 查询索引是customer的所有文档(所有数据),并且以age参数值正序排序,默认是10条数据
# 指定返回参数查询
GET /customer/_search
{
  "query": { "match_all": {} },
  "_source": ["name", "age"]
}
# 结果(结果摘取),在_source中只有设置的参数
"hits" : [
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "qKIc3n4BeDUfn7IZFYOH",
        "_score" : 1.0,
        "_source" : {
          "name" : "小白象啊",
          "age" : 26
        }
      },
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "name" : "娃哈哈",
          "age" : "23"
        }
      }
    ]
# 查询指定参数值的数据,年龄是26的数据
# 执行:
GET /customer/_search
{
  "query": { "match": { "age": 26 } }
}
# 查询姓名中包含 ‘小’ 的数据
GET /customer/_search
{
  "query": { "match": { "name": "小" } }
}
# 此查询es默认返回包含 大、川、大川的数据,match是分词的
GET /customer/_search
{
  "query": { "match": { "name": "大川" } }
}
# 结果(摘取片段)
"hits" : [
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "10",
        "_score" : 1.3862944,
        "_source" : {
          "name" : "大汝州",
          "birthday" : "2010-06-01",
          "age" : "27"
        }
      },
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "11",
        "_score" : 1.3862944,
        "_source" : {
          "name" : "大蟒川",
          "birthday" : "2010-05-01",
          "age" : "22"
        }
      }
    ]
# 不分词查询
GET /customer/_search
{
  "query": { "match_phrase": { "name": "大川" } }
}
# 指定全匹配查询,数据中的name值必须包含大、小、川的才能查出来
GET /customer/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "大" } },
        { "match": { "name": "小" } },
        { "match": { "name": "川" } }
      ]
    }
  }
}
# 包含大或者川的都可以
GET /customer/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "大" } },
        { "match": { "name": "川" } }
      ]
    }
  }
}
# 不包含查询,结果是不包含大和川的数据
GET /customer/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "name": "大" } },
        { "match": { "name": "川" } }
      ]
    }
  }
}
# 多条件查询,表示查询age=26并且名称不包含鸟的
GET /customer/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "26" } }
      ],
      "must_not": [
        { "match": { "name": "鸟" } }
      ]
    }
  }
}
# 过滤条件查询(范围查询),查詢年龄3-30的数据(包含3和30)
GET /customer/_search
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "age": {
            "gte": 3,
            "lte": 30
          }
        }
      }
    }
  }
}

聚合查询

# 查询出name包含哈的所有数据
GET /customer/_search
{
  "size": 0,
  "query": { "match": { "name": "哈" } },
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "name.keyword"
      }
    }
  }
}
# 结果:
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.9061548,
    "hits" : [
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "5",
        "_score" : 1.9061548,
        "_source" : {
          "name" : "娃哈哈",
          "birthday" : "2020-01-01",
          "age" : "23"
        }
      },
      {
        "_index" : "customer",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.9530774,
        "_source" : {
          "name" : "娃哈哈",
          "age" : "33"
        }
      }
    ]
  },
  "aggregations" : {
    "group_by_state" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "娃哈哈",
          "doc_count" : 2
        }
      ]
    }
  }
}
# 查询分组结果并返回相同名称数据的数量,size是hits中的数量,其中group_by_state是可以定义的,建议是:group_by_+分组字段名
GET /customer/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "name.keyword"
      }
    }
  }
}
# 结果片段
"aggregations" : {
    "group_by_state" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "娃哈哈",
          "doc_count" : 2
        }
      ]
    }
  }
# 分组查询并求指定参数平均值
GET /customer/_search
{
  "size": 0,
  "aggs": {
    "group_by_name": {
      "terms": {
        "field": "name.keyword"
    },
    "aggs": {
        "average_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
}

更多查询方式官网
下一篇:Elasticsearch Java REST Client 初始化、添加索引及数据