Elasticsearch及ELK使用(一):分析搜索引擎入门

本文是Elasticsearch及其Elastic Stack的入门教程,介绍了什么是Elasticsearch、Elastic Stack的组成及使用场景。详细讲解了Elasticsearch的基本概念,如文档、索引、节点、分片和副本。此外,还涵盖了Linux环境下ELK的安装过程,包括Elasticsearch、Kibana的配置与启动。内容还包括如何使用Elasticsearch进行数据操作、搜索、聚合等,以及集群搭建的步骤。最后讨论了中文分词和全文搜索的相关知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 引言

1.1 什么是elasticsearch?

ElasticSearch是一个分布式,高性能、高可用、可伸缩的搜索和分析系统 。
更准确说它是向量数据库(Vector Database), 与关系型数据库“精准确定”特性不同,向量数据库适合计算相似性,特别是语义逻辑级的相关性(相似性),而不是字面文本的相同性,所以适合应用于搜索引擎。

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

1.2 什么是Elastic Stack套件?

单纯的elasticsearch提供了数据搜索分析,但是:

  • 它仅提供了RESTful API,没有提供界面,不太方便,所以通常安装kibana组件提供Web界面,包括操作和监控等。
  • elasticsearch不具备数据采集功能,通常通过在源端系统部署filebeat采集数据(包括从文件和数据库中采集等),filebeat采集得到的数据可以直接传给elasticsearch。还可以filebeat采集的数据先通过logstash,在logstash里完成加工、过滤、转换等预处理再传给elasticsearch。

所以在实际使用中,经常以套件组合形式使用。

Elastic Stack,前身缩写是ELK,就是ElasticSearch + LogStash + Kibana。 现在的Elastic Stack除了下图右侧的ELK,还包括左侧的主键。
在这里插入图片描述

1.3 ES的使用场景

  • 网上商场,搜索商品.
  • ES配合logstash,kibana,日志分析.
    假设用数据库做搜索,当用户在搜索框输入“四川火锅”时,数据库通常只能把这四个字去进行全部匹配。可是在文本中,可能会出现“推荐四川好吃的火锅” 或者“火锅在四川的特色”、或者“Sichuan hot pot”,这时候就没有结果了。

而且:
1.海量数据组合条件查询
2.毫秒级或者秒级返回数据

2 elasticsearch基本概念

2.1 近实时(NRT)

ES是一个近实时的搜索引擎(平台),代表着从添加数据到能被搜索到只有很少的延迟。(大约是1s)这里的延迟是搜索search的延迟,直接查询query是无延迟的。

2.2 文档document

Elasticsearch是面向文档的,文档是所有可搜索数据的最小单元。可以把文档简单理解为关系型数据库中的一条记录Record。每个文档有唯一的ID,文档会被序列化成json格式,保存在Elasticsearch中。同样json对象由字段组成,给个字段都有自己的类型(字符串,数值,布尔,二进制,日期范围类型)。当我们创建文档时,如果不指定类型,Elasticsearch会帮我们自动匹配类型。每个文档都一个ID,你可以自己指定,也可以让Elasticsearch自动生成。json格式,支持数组/嵌套,在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。
多个文档的集合称作Collection。类似于关系数据库中的Table。

2.4 类型type(Deprecated)

多个文档的集合称作Collection(Collection类似于关系数据库中的Table),但在Elasticsearch中Collection被称为type。

从6.0开始,type已经被逐渐废弃。在6.0中默认类型(_doc)。(虽然在6.0中,一个index还可以创建多个types,但不推荐这么做)

从7.0开始,一个索引下默认有且只有一个类型(_doc),不能自行创建类型。

2.3 索引index

与关系数据库的index用途类似,Elasticsearch中index的目的也是为加快检索的一种特定的数据结构,使得能够高效快速的得到检索结果。
在关系数据库中,index与数据是分离的,index是辅助地位,index可以没有也可以多个,获取数据既可以通过index也可以直接获取。
但在向量数据库中,index是必须的,无法直接检索数据,因为是通过相关性检索数据,必须通过index进行检索,在向量数据库中,index不是辅助地位,而是变成了对Collection的更高级的组织,以上Collection(或称为type)是下挂在索引之中。在向量数据库中index可类似于关系数据库中的schema。
在Elasticsearch中index由一个名称(必须全部是小写)标识。Index体现了逻辑空间的概念,每个索引都有自己的mapping定义,用于定义包含文档的字段名和字段类型。

索引的mapping和setting

  1. mapping:定义文档字段的类型
  2. setting:定义不同数据的分布

以上,不恰当的类比:
关系数据库 : Schema模式 ⇒ Table表 ⇒ Record记录 ⇒ Columns列
Elasticsearch : 索引Index ⇒ 类型type ⇒ 文档 document ⇒ 字段Fields

2.5 节点node

从部署维度,节点是一个Elasticsearch实例,本质上就是一个java进程,节点也有一个名称(默认是随机分配的),当然也可以通过配置文件配置,或者在启动的时候,-E node.name=node1指定。此名称对于管理目的很重要,因为您希望确定网络中的哪些服务器对应于ElasticSearch集群中的哪些节点。

在Elasticsearch中,节点的类型主要分为如下几种:

  • master eligible节点:

    每个节点启动后,默认就是master eligible节点,可以通过node.master: false 禁止

    master eligible可以参加选主流程,成为master节点

    当第一个节点启动后,它会将自己选为master节点

    每个节点都保存了集群的状态,只有master节点才能修改集群的状态信息

  • data节点

    可以保存数据的节点。负责保存分片数据,在数据扩展上起到了至关重要的作用

  • Coordinating 节点

    负责接收客户端请求,将请求发送到合适的节点,最终把结果汇集到一起

    每个节点默认都起到了Coordinating node的职责

开发环境中一个节点可以承担多个角色,生产环境中,建议设置单一的角色,可以提高性能等

2.6 分片shards

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

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

为什么要分片?

  • 它允许您水平拆分/缩放内容量
  • 它允许您跨碎片(可能在多个节点上)分布和并行操作,从而提高性能/吞吐量

如何分配分片以及如何将其文档聚合回搜索请求的机制完全由ElasticSearch管理,并且对作为用户的您是透明的。主分片数在索引创建时指定,后续不允许修改,除非Reindex

2.7 分片的副本replicas of shard

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

为什么要有副本?

  • 当分片/节点发生故障时提供高可用性。因此,需要注意的是,副本分片永远不会分配到复制它的原始/主分片所在的节点上。
  • 允许您扩展搜索量/吞吐量,因为可以在所有副本上并行执行搜索。

总而言之,每个索引可以分割成多个分片。索引也可以零次(意味着没有副本)或多次复制。复制后,每个索引将具有主分片(从中复制的原始分片)和副本分片(主分片的副本)。

可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,您还可以随时动态更改副本的数量。您可以使用收缩和拆分API更改现有索引的分片数量,建议在创建索引时就考虑好分片和副本的数量。

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

3 Linux ELK的安装

高版本还是低版本elasticssearch,都不要使用root用户安装和启动,使用root用户启动是极不好的习惯。

注意从elasticssearch7.0开始,它会自动检测,若roott用户启动会提示失败。

3.1 规划

  1. elasticsearch的版本几个月就升一个大版本号,版本号变得太快。 实际上高版本大同小异。这里以6.8.3为例。ELK三件套的版本号和filebeat的版本号应该完全一致,避免兼容性问题。
  2. 确保Linux已经安装了JDK(含JVM),推荐使64bit的的 1.8.0_131或更高的版本JVM。
  3. 由于ELK三件套通常安装在一起(同一台机器上),因此我们先建立一个elk文件夹,在elk文件夹下分别有三个子目录放不同的软件,结构如下:

elk
∟ elasticsearch-6.8.3

∟ kibana-6.8.3-linux-x86_64

∟ logstash-6.8.3

3.2 操作系统调整

elasticsearch对操作系统配置有要求,不然启动时会报错。

  • 操作系统默认的max_map_count[65530]太低,至少增加到[262144]。使用root用户vim /etc/sysctl.conf 文件中增加以下配置
vm.max_map_count=262145

然后root用户执行:sysctl -p 使配置生效

  • 最大文件描述符[4096]对于elasticsearch进程可能太低,至少增加到[65535] 使用root用户vim /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
* soft nproc 4096
* hard nproc 4096

修改后,重新登录通常即可生效,可是使用ulimit -a 查看当前值

  • 注意防火墙。需要配置防火墙端口,或者关闭防火墙。

3.2 elasticsearch安装

  1. (非root用户)登录linux,下载最新的elasticsearch包 下载地址https://www.elastic.co/cn/downloads/elasticsearch 。然后解压即可

    cd /home/zyplanke/elk
    curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.8.3.tar.gz
    tar -xvf elasticsearch-6.8.3.tar.gz
    
  2. 配置elasticsearch的配置。编辑vim config/elasticsearch.yml

    cluster.name: mycluster     # 集群名,所有节点node都应配置相同的集群名
    node.name: node1   # 本节点名,同一集群下不同的node名字不能重复
    network.host: 0.0.0.0  # 本节点监听本地IP,全零为本地所有网卡
    http.port: 9200  # http 协议的端口
    transport.tcp.port: 9301   # 集群内节点之间的通信端口。
    path.data: /elasticsearch/data  # 数据存放的路径(目录需要提前创建好,确保有权限)
    path.logs: /elasticsearch/logs  # 日志存放的路径(目录需要提前创建好,确保有权限)
    
  3. 调整elasticsearch使用的jvm内存大小(可不调整,可选步骤) vim config/jvm.options

    -Xms1g
    -Xmx1g
    
  4. elasticsearch使用了log4j2作为日志配置,如需要可调整日志配置(可选步骤)vim config/log4j2.properties

  5. 进入解压后的 elasticsearch文件夹的bin目录下 执行./elasticsearch 启动

  6. 启动后,可以通过浏览器访问http://192.168.43.201:9200/,正常结果如下,表明elasticsearch启动成功。

在这里插入图片描述

3.3 浏览器插件elasticsearch-head(可选)

这时一款chrome浏览器的插件,可以图形化监视和管理elasticsearch。需要在google应用商店下载插件安装(需翻墙):
在这里插入图片描述

3.4 kibana安装

  1. (非root用户)登录linux,下载最新的kibana包 下载地址https://www.elastic.co/cn/downloads/elasticsearch 。然后解压即可

    cd /home/zyplanke/elk
    curl -L -O https://artifacts.elastic.co/downloads/kibana/kibana-6.8.3-linux-x86_64.tar.gz
    tar -xvf kibana-6.8.3-linux-x86_64.tar.gz
    
  2. 配置kibana的配置。编辑vim config/kibana.yml

    server.port: 5601     # kibana的监听端口,可通过浏览器访问
    server.host: "0.0.0.0"   # kibana监听本地IP,全零为本地所有网卡
    elasticsearch.hosts: ["http://192.168.43.201:9200"]    # kibana的连接ES的地址,ES为集群,则应配多个(每个节点均配置)
    
  3. 进入解压后的 kibana文件夹的bin目录下 执行./kibana启动

  4. 启动后,可以通过浏览器访问http://192.168.43.201:5601/,(稍等片刻)正常结果如下,表明kibana启动成功
    在这里插入图片描述

4 使用elasticsearch

4.1 写请求原理

在这里插入图片描述

以下是写单个文档所需的步骤:
(1 )客户端向 NODE I 发送写请求。

(2)检查Active的Shard数。

(3) NODEI 使用文档 ID 来确定文档属于分片 0,通过集群状态中的内容路由表信息获知分片 0 的主分片位于 NODE3 ,因此请求被转发到 NODE3 上。

( 4 ) NODE3 上的主分片执行写操作 。 如果写入成功,则它将请求并行转发到 NODE I 和
NODE2 的副分片上,等待返回结果 。当所有的副分片都报告成功, NODE3 将向协调节点报告
成功,协调节点再向客户端报告成功 。
在客户端收到成功响应时 ,意味着写操作已经在主分片和所有副分片都执行完成。

1. 为什么要检查Active的Shard数?

ES中有一个参数,叫做waitforactiveshards,这个参数是Index的一个setting,也可以在请求中带上这个参数。这个参数的含义是,在每次写入前,该shard至少具有的active副本数。假设我们有一个Index,其每个Shard有3个Replica,加上Primary则总共有4个副本。如果配置waitforactiveshards为3,那么允许最多有一个Replica挂掉,如果有两个Replica挂掉,则Active的副本数不足3,此时不允许写入。

这个参数默认是1,即只要Primary在就可以写入,起不到什么作用。如果配置大于1,可以起到一种保护的作用,保证写入的数据具有更高的可靠性。但是这个参数只在写入前检查,并不保证数据一定在至少这些个副本上写入成功,所以并不是严格保证了最少写入了多少个副本。

在以前的版本中,是写一致性机制,现被替换为waitforactiveshards

one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行
all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
quorum:要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作

写一致性的默认策略是 quorum,即多数的分片(其中分片副本可以是主分片或副分片)在
写入操作时处于可用状态。

put /index/type/id?consistency=quorum
quroum = int( (primary + number_of_replicas) / 2 ) + 1
参数简 介
version设置文档版本号。主要用于实现乐观锁
version_type详见版本类型
op_type可设置为 create 。 代表仅在文档不存在时才写入 。 如果文档己存在,则写请求将失败
routingES 默认使用文档 ID 进行路由,指定 routing 可使用 routing 值进行路由
wait_for_active_shards用于控制写一致性,当指定数量的分片副本可用时才执行写入,否则重试直至超时 。默认为 l , 主分片可用 即执行写入
refresh写入完毕后执行 refresh ,使其对搜索可见
timeout请求超时时间 , 默认为 l 分钟
pipeline指定事先创建好的 pipeline 名称

写入Primary完成后,为何要等待所有Replica响应(或连接失败)后返回

在更早的ES版本,Primary和Replica之间是允许异步复制的,即写入Primary成功即可返回。但是这种模式下,如果Primary挂掉,就有丢数据的风险,而且从Replica读数据也很难保证能读到最新的数据。所以后来ES就取消异步模式了,改成Primary等Replica返回后再返回给客户端。

因为Primary要等所有Replica返回才能返回给客户端,那么延迟就会受到最慢的Replica的影响,这确实是目前ES架构的一个弊端。之前曾误认为这里是等waitforactive_shards个副本写入成功即可返回,但是后来读源码发现是等所有Replica返回的。

如果Replica写入失败,ES会执行一些重试逻辑等,但最终并不强求一定要在多少个节点写入成功。在返回的结果中,会包含数据在多少个shard中写入成功了,多少个失败了

4.2 操作方式

以下操作,可以在支持RESTful的工具上执行(如curl或其他工具),也可以在kibana界面上的“Dev tools”上执行以下操作。
在这里插入图片描述

4.3 索引index操作

4.3.1 创建索引

创建索引名为idx_taibai的索引(还没有数据)

PUT /idx_taibai   
{
	"settings": {
		"number_of_shards": "2",   //分片数
		"number_of_replicas": "0",  //副本数
		"write.wait_for_active_shards": 1
	}
}

查看索引:

GET /idx_taibai/_settings

4.3.2 修改索引属性

索引的一些设置可以修改,例如replicas副本数,但shards分片数不能修改。

PUT /idx_taibai/_settings
{
    "number_of_replicas" : "2"
}

4.3.3 删除索引

DELETE /idx_taibai

4.4 文档数据document操作

4.4.1 插入数据(文档)

在elasticsearch中的数据最小单位就是文档document。每个文档有不重复的ID。

//插入一个文档,且显示指定文档id。  (下面的_doc是type,固定为这几个字母)
POST /idx_taibai/_doc/1001
{
  "id":1001,    // 上面URL的ID是elasticsearch认可的文档ID,这里的id同其他域一样,仅仅是普通是一个数据域,仅名字不同而已。
  "name":"张三",
  "age":20,
  "sex":"男"
}

//插入一个文档,不显示指定id,由elasticsearch帮我们自动生成文档ID。  (下面的_doc是type,固定为这几个字母)
POST /idx_taibai/_doc
{
  "id":1002,  
  "name":"三哥",
  "age":20,
  "sex":"男"
}

4.4.2 查看数据

根据指定的文档ID,查看某个文档

GET /idx_taibai/_doc/1001

不仅指定文档ID,还指定文档中key-value属性,例如只返回name数据域:

GET /idx_taibai/_doc/1001?_source=name

4.4.3 更新数据

在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新

PUT /idx_taibai/_doc/1001
{
  "id":1009,
  "name":"太白",
  "age":21,
  "sex":"男"
}

注意:没更新一次,该文档的_version值是在递增的。

局部更新

其实Elasticsearch内,对部分更新partial update的实际执行和传统的全量替换方式是几乎一样的,其步骤如下

  1. 内部先获取到对应的document;
  2. 将传递过来的field更新到document的json中(这一步实质上也是一样的);
  3. 将老的document标记为deleted(到一定时候才会物理删除);
  4. 将修改后的新的document创建出来
POST /idx_taibai/_doc/1001/_update
{
  "doc":{
     "age":23
  }
}

替换和更新的不同:替换是每次都会去替换,更新是有新的东西就更新,没有新的修改就不更新,更新比替换的性能好

4.4.4 删除数据

DELETE /idx_taibai/_doc/1001

4.5 基本搜索操作

4.5.1 搜索全部数据

// 默认最多返回10条数据
GET /idx_taibai/_search    

返回结果中:

took Elasticsearch运行查询需要多长时间(以毫秒为单位)
timed_out 搜索请求是否超时
_shards 搜索了多少碎片,并对多少碎片成功、失败或跳过进行了细分。
max_score 找到最相关的文档的得分
hits.total.value 找到了多少匹配的文档
hits.sort 该文档的排序位置(当不根据相关性得分排序时)
hits._score 该文档的相关性评分(在使用match_all时不适用)

带参数搜索 (按age排序)

GET /idx_taibai/_search
{
  "query": { "match_all": {} },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

4.5.2 关键字搜索数据

elasticsearch中有两种搜索方式:

  • 通过url 搜索。 顾名思义, url搜索的参数都通过url来传递,方便来进行一般的数据查看。
  • 通过的 DSL(Domain Specific Language) 来定义查询语言。 在请求的requestBody中定义。DSL可以非常灵活,从而实现比较高级的搜索。

查询年龄等于20的(这时基于URL的搜索)

GET /idx_taibai/_search?q=age:20    

4.5.3 DSL搜索

查询年龄等于20的(这时基于DLS的搜索)

GET /idx_taibai/_search
{
  "query" : {
    "match" : {       //查询年龄等于20的
      "age" : 20
    }
  }
}

再例如:

//查询地址等于mill或者lane
GET /idx_taibai/_search
{
  "query": { "match": { "address": "mill lane" } }
}

//查询地址等于(mill lane)的
GET /idx_taibai/_search
{
  "query": { "match_phrase": { "address": "mill lane" } }
}

//注意:match 中如果加空格,那么会被认为两个单词,包含任意一个单词将被查询到
//match_parase 将忽略空格,将该字符认为一个整体,会在索引中匹配包含这个整体的文档。
//查询年龄大于20  并且性别是男的
GET /idx_taibai/_search    
{
  "query": {
    "bool": {
      "filter": {
        "range": {
            "age": {
              "gt": 20
            }
          }
        },
      "must": {
        "match": {
          "sex": "男"
        }
      }
    }
  }
}   

4.5.4 高亮显示

GET /idx_taibai/_search   			
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

4.6 聚合搜索操作

https://www.elastic.co/guide/en/elasticsearch/reference/7.x/search-aggregations.html

avg :平均值

max:最大值

min:最小值

sum:求和

例如:查询平均年龄 (如果不指定size等于0,则还会返回10条数据)

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {   //自定义名字
      "avg": {    //什么类型
        "field": "age"    //那个字段
      }
    }
  },
  "size": 0
}

使用脚本

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {
      "avg": {
        "script": {
          "source": "doc.age.value"
        }
      }
    }
  },
  "size": 0
}

cardinality : 去重统计。例如:

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {
      "cardinality": {
        "field": "age"
      }
    }
  },
  "size": 0
}

extended_stats扩展统计聚合

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {
      "extended_stats": {
        "field": "age"
      }
    }
  },
  "size": 0
}

value_count值计数统计

可以理解为统计个数

terms词聚合

基于某个field,该 field 内的每一个【唯一词元】为一个桶,并计算每个桶内文档个数。默认返回顺序是按照文档个数多少排序。

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {
      "terms": {
        "field": "age"
      }
    }
  },
  "size": 0
}

top_hits最高匹配权值聚合

获取到每组前n条数据,相当于sql 中Top(group by 后取出前n条)。它跟踪聚合中相关性最高的文档

GET /idx_taibai/_search
{
  "aggs": {
    "taibai": {
      "terms": {
        "field": "age"
      },
      "aggs": {
        "count": {
          "top_hits": {
            "size": 3
          }
        }
      }
    }
  },
  "size": 0
}

range范围分段

GET /idx_taibai/_search
{
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      }
    }
  },
  "size": 0
}

4.7 查询结果设置

4.7.1 指定返回结果字段

 //只返回id和name字段
GET /idx_taibai/_doc/1001?_source=id,name   

4.7.2 去掉元数据

去掉元数据,只需要该文档真实的key-value数据。

GET /idx_taibai/_doc/1001/_source

4.7.3 判断文档是否存在

使用HEAD返回码为HTTP的返回码。

HEAD /idx_taibai/_doc/1001

4.8 批量操作

语法格式

POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

(具体略)

4.9 结构化查询

4.9.1 term查询

term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):

GET /idx_taibai/_search
{
  "query" : {
    "term" : {
      "age" : 20
    }
  }
}

4.9.2 terms查询

terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去
做匹配:

GET /idx_taibai/_search
{
  "query" : {
    "terms" : {
      "age" : [20,27]
    }
  }
}

4.9.3 range查询

range 过滤允许我们按照指定范围查找一批数据:

gt :: 大于
gte :: 大于等于
lt :: 小于
lte :: 小于等于

GET /idx_taibai/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 20,
        "lte": 22
      }
    }
  }
}

4.9.4 exists查询

exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件

包含这个字段就返回返回这条数据

GET /idx_taibai/_search
{
  "query": {
    "exists": {
      "field": "name"
    }
  }
}

4.9.5 match查询

match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符;如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你
给定的值:

GET /idx_taibai/_search
{
  "query" : {
    "match" : {     
      "name" : "三个小矮人"
    }
  }
}
match查询会先对搜索词进行分词,分词完毕后再逐个对分词结果进行匹配,因此相比于term的精确搜索,match是分词匹配搜索

4.9.6 bool查询

bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符:
must :: 多个查询条件的完全匹配,相当于 and 。
must_not :: 多个查询条件的相反匹配,相当于 not 。
should :: 至少有一个查询条件匹配, 相当于 or 。
这些参数可以分别继承一个查询条件或者一个查询条件的数组:

GET /idx_taibai/_search
{
	"query": {
		"bool": {
			"must": {
				"term": {
					"sex": "男"
				}
			},
			"must_not": {
				"term": {
					"age": "29"
				}
			},
			"should": [
			  {
					"term": {
						"sex": "男"
					}
				},
				{
					"term": {
						"id": 1003
					}
				}
			]
		}
	}
}

4.9.7 过滤查询

查询年龄为20岁的用户。

GET /idx_taibai/_search
{
	"query": {
		"bool": {
			"filter": {
				"term": {
					"age": 20
				}
			}
		}
	}
}

4.10 批量导入测试数据

该数据是使用www.json- http://generator.com/生成的,因此请忽略数据的实际值和语义,因为它们都是随机生成的。您可以从这里下载示例数据集(accounts.json)。将其提取到当前目录,然后按如下方式将其加载到集群中:

curl -H "Content-Type: application/json" -XPOST "localhost:9200/idx_taibai/_bulk?pretty&refresh" --data-binary "@accounts.json"

官方文档练习案例:

1.给指定id加点年龄(age)

2.执行match_all操作,并按帐户余额降序对结果进行排序,并返回前10个

3.如何从搜索中返回两个字段,即帐号和余额

4.返回帐户为20的

5.回地址中包含“mill”的所有帐户

6.返回地址中包含“mill”或“lane”的所有帐户

7.返回地址中包含“mill”和“lane”的所有帐户

8.地址中既不包含“mill”也不包含“lane”的所有帐户

9.返回所有40岁但不居住在ID的人(state不等于ID)的账户

10.使用bool查询返回余额在20000到30000之间的所有帐户,包括余额。换句话说,我们希望找到余额大于或等于20000,小于或等于30000的账户

11.按状态(state)对所有帐户进行分组,然后返回按count降序排列的前10个

12.按状态计算平均帐户余额(同样只针对按count降序排列的前10个状态)

13.基于之前(12)的聚合,我们现在按降序对平均余额排序

14.按照年龄等级(20-29岁,30-39岁,40-49岁)分组,然后按性别分组,最后得到每个年龄等级,每个性别的平均账户余额

(以上来源于官方文档,具体操作的例子见官方文档)

4.11 其他

4.11.1 分页查询

// size: 结果数,默认10      from: 跳过开始的结果数,默认0
GET /idx_taibai/_search?size=1&from=2    

4.11.2 浏览器

如果使用浏览器去查询,若返回的json没有格式化,可在后面加参数pretty,返回格式化后的数据

http://192.168.204.209:9200/idx_taibai/_doc/1001?pretty

5.中文分词

5.1 Analyzer 的组成

  • Character Filters (针对原始文本处理,例如,可以使用字符过滤器将印度阿拉伯数字( )转换为其等效的阿拉伯语-拉丁语(0123456789))
  • Tokenizer(按照规则切分为单词),将把文本 “Quick brown fox!” 转换成 terms [Quick, brown, fox!],tokenizer 还记录文本单词位置以及偏移量。
  • Token Filter(将切分的的单词进行加工、小写、刪除 stopwords,增加同义词)

5.2 elasticsearch内置分词器

Standard默认分词器 按词分类 小写处理
Simple按照非字母切分,非字母则会被去除 小写处理
**Stop **小写处理 停用词过滤(the,a, is)
**Whitespace **按空格切分
**Keyword **不分词,当成一整个 term 输出
**Patter **通过正则表达式进行分词 默认是 \W+(非字母进行分隔)
**Language **提供了 30 多种常见语言的分词器

5.3 分词api

POST /_analyze
{
  "analyzer":"standard",
  "text":"tai bai"
}

POST /_analyze
{
  "analyzer":"standard",
  "text":"决战到天亮"
}

英文分词 一般以空格分隔,中文分词的难点在于,在汉语中没有明显的词汇分界点,如果分隔不正确就会造成歧义。

常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器。

5.4 ik分词器安装

IK分词器 Elasticsearch插件地址:https://github.com/medcl/elasticsearch-analysis-ik

注意选择对应es的版本,如6.8.3

在这里插入图片描述

1.下载项目 zip包
在这里插入图片描述

2.解压项目

3.进入项目跟目录 使用maven编译打包此项目
在这里插入图片描述

mvn clean
mvn compile
mvn package

4.执行完上面命令后 在{project_path}/elasticsearch-analysis-ik/target/releases/elasticsearch-analysis-ik-*.zip会有个zip,上传到linux elasticsearch 插件目录, 如: plugins/ik 注意在plugins下新建ik目录 将zip包上传到ik目录下

在这里插入图片描述

5.使用unzip命令解压zip包,没有unzip的 可先下载unzip 命令:yum install -y unzip zip

6.解压之后删除原来的zip包

7.检查是否需要修改版本信息

vim {path}/plugins/ik/plugin-descriptor.properties
在这里插入图片描述

8.重启 ik插件安装完成
在这里插入图片描述

9.测试中文分词器效果

POST /_analyze
{
  "analyzer": "ik_max_word",   或者  //ik_smart
  "text": "决战到天亮"
}

5.5 拼音分词器

1.下载对应版本的zip包https://github.com/medcl/elasticsearch-analysis-pinyin/releases

2.可在Windows解压好,在plugins下创建pinyin文件夹

3.将解压内容放置在pinyin文件夹,重启

5.6 自定义分词器

接受参数

tokenizer一个内置的或定制的tokenizer。(必需)
char_filter一个可选的内置或自定义字符过滤器数组。
filter一个可选的内置或定制token过滤器数组。
PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom", 
          "tokenizer": "standard",
          "char_filter": [
            "html_strip"     //过滤HTML标签
          ],
          "filter": [
            "lowercase",    //转小写
            "asciifolding"  //ASCII-折叠令牌过滤器  例如 à to a
          ]
        }
      }
    }
  }
}


POST my_index/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "Is this <b>déjà vu</b>?"
}

创建一个中文+拼音的分词器(中文分词后拼音分词)

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ik_pinyin_analyzer": {
          "type": "custom",
          "tokenizer": "ik_smart",
          "filter": [
            "pinyin_max_word_filter"
          ]
        },
        "ik_pingying_smark": {
          "type": "custom",
          "tokenizer": "ik_smart",
          "filter": [
            "pinyin_smark_word_filter"
          ]
        }
      },
      "filter": {
        "pinyin_max_word_filter": {
          "type": "pinyin",
          "keep_full_pinyin": "true",  #分词全拼如雪花 分词xue,hua
          "keep_separate_first_letter": "true",#分词简写如雪花 分词xh
          "keep_joined_full_pinyin": true  #分词会quanpin 连接 比如雪花分词 xuehua
        },
        "pinyin_smark_word_filter": {
          "type": "pinyin",
          "keep_separate_first_letter": "false", #不分词简写如雪花 分词不分词xh
          "keep_first_letter": "false"     #不分词单个首字母 如雪花 不分词 x,h
        }
      }
    }
  }
}


PUT /my_index/_mapping
  {
  "properties": {
      "productName": {
          "type": "text",
          "analyzer": "ik_pinyin_analyzer",  #做文档所用的分词器
          "search_analyzer":"ik_pingying_smark"   #搜索使用的分词器
      }
  }
}

POST /my_index/_doc
{
  "productName": "雪花啤酒100L"
}


GET /my_index/_search
{
  "query": {
    "match": {
      "productName": "雪Hua"
    }
  }
}

6 全文搜索

6.1 构建数据

PUT /test
{
	"settings": {
		"index": {
			"number_of_shards": "1",
			"number_of_replicas": "0"
		}
	},
	"mappings": {
		"properties": {
			"age": {
				"type": "integer"
			},
			"email": {
				"type": "keyword"
			},
			"name": {
				"type": "text"
			},
			"hobby": {
				"type": "text",
				"analyzer": "ik_max_word"
			}
		}
	}
}



POST _bulk
{ "create" : { "_index" : "test","_id": "1000"} }
{"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
{ "create" : { "_index" : "test","_id": "1001"} }
{"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
{ "create" : { "_index" : "test","_id": "1002"} }
{"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
{ "create" : { "_index" : "test","_id": "1003"} }
{"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳、篮球"}
{ "create" : { "_index" : "test","_id": "1004"} }
{"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影、羽毛球"}

6.2 单词搜索

GET /test/_search
{
	"query": {
		"match": {
			"hobby": "音乐"
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

6.3 多词搜索

//搜索包含音乐和篮球的
GET /test/_search
{
	"query": {
		"match": {
			"hobby": "音乐 篮球"
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

//搜索包含音乐还有篮球的(and)
GET /test/_search
{
	"query": {
		"match": {
			"hobby": {
				"query": "音乐 篮球",
				"operator": "and"
			}
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}


GET /goods/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "price": {
              "gte": 1000,
              "lte": 2000
            }
          }
        },
        {
          "match": {
            "name": "2018女鞋"
          }
        },
        {
          "match": {
            "spec": "红色 黑色"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "spec": "蓝色"
          }
        }
      ]
    }
  }
}

//在Elasticsearch中也支持这样的查询,通过minimum_should_match来指定匹配度,如:70%;
GET /test/_search
{
	"query": {
		"match": {
			"hobby": {
				"query": "游泳 羽毛球",
				"minimum_should_match": "70%"
			}
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

6.4 组合搜索

//搜索结果中必须包含篮球,不能包含音乐,如果包含了游泳,那么它的相似度更高。
GET /test/_search
{
	"query": {
		"bool": {
			"must": {
				"match": {
					"hobby": "篮球"
				}
			},
			"must_not": {
				"match": {
					"hobby": "音乐"
				}
			},
			"should": [{
				"match": {
					"hobby": "游泳"
				}
			}]
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}


//默认情况下,should中的内容不是必须匹配的,如果查询语句中没有must,那么就会至少匹配其中一个。当然了,
也可以通过minimum_should_match参数进行控制,该值可以是数字也可以的百分比。
//minimum_should_match为2,意思是should中的三个词,至少要满足2个

GET /test/_search
{
	"query": {
		"bool": {
			"should": [{
					"match": {
						"hobby": "游泳"
					}
				},
				{
					"match": {
						"hobby": "篮球"
					}
				},
				{
					"match": {
						"hobby": "音乐"
					}
				}
			],
			"minimum_should_match": 2
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

6.5 权重

搜索关键字为“游泳篮球”,如果结果中包含了“音乐”权重为10,包含了“跑步”权重为2。

GET /test/_search
{
	"query": {
		"bool": {
			"must": {
				"match": {
					"hobby": {
						"query": "游泳篮球",
						"operator": "and"
					}
				}
			},
			"should": [{
					"match": {
						"hobby": {
							"query": "音乐",
							"boost": 10
						}
					}
				},
				{
					"match": {
						"hobby": {
							"query": "跑步",
							"boost": 2
						}
					}
				}
			]
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

7 Elasticsearch集群

7.1 三台机器大家集群

192.168.204.209 elasticsearch.yml

cluster.name: mycluster     # 集群名,所有节点node都应配置相同的集群名
node.name: node1   # 本节点名,同一集群下不同的node名字不能重复
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9200
#参数设置一系列符合主节点条件的节点的主机名或 IP 地址来引导启动集群。
cluster.initial_master_nodes: ["node1"]
# 设置新节点被启动时能够发现的主节点列表(主要用于不同网段机器连接)
discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"]
# 该参数就是为了防止”脑裂”的产生。定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。
discovery.zen.minimum_master_nodes: 2
# 解决跨域问题配置
http.cors.enabled: true
http.cors.allow-origin: "*"

192.168.204.203 elasticsearch.yml

cluster.name: mycluster     # 集群名,所有节点node都应配置相同的集群名
node.name: node2   # 本节点名,同一集群下不同的node名字不能重复
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9200
cluster.initial_master_nodes: ["node1"]
discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"

192.168.204.108 elasticsearch.yml

cluster.name: mycluster     # 集群名,所有节点node都应配置相同的集群名
node.name: node3   # 本节点名,同一集群下不同的node名字不能重复
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9200
cluster.initial_master_nodes: ["node-1"]
discovery.zen.ping.unicast.hosts: ["192.168.204.209","192.168.204.203","192.168.204.108"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"

启动后效果
在这里插入图片描述

7.2 一台机器搭建集群(一)

注意修改jvm.options

在这里插入图片描述

elasticsearch-7.3.2_node1

cluster.name: luban
node.name: node-1
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
cluster.initial_master_nodes: ["node-1"]
discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"

elasticsearch-7.3.2_node2

cluster.name: luban
node.name: node-2
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9201
transport.port: 9301
cluster.initial_master_nodes: ["node-1"]
discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"

elasticsearch-7.3.2_node3

cluster.name: luban
node.name: node-3
node.master: true
node.data: true
network.host: 0.0.0.0
http.port: 9202
transport.port: 9302
cluster.initial_master_nodes: ["node-1"]
discovery.seed_hosts: ["192.168.204.209:9300", "192.168.204.209:9301","192.168.204.209:9302"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"

分别启动:

./elasticsearch -p /tmp/elasticsearch_9200_pid -d
./elasticsearch -p /tmp/elasticsearch_9201_pid -d
./elasticsearch -p /tmp/elasticsearch_9202_pid -d

7.3 一台机器搭建集群(二)

在这里插入图片描述

新建目录:
在这里插入图片描述
在这里插入图片描述
注意赋予权限

chown -R taibai:taibai ES

分别启动:

./elasticsearch -d  -E node.name=node-1 -E http.port=9200 -E transport.port=9300 -E path.data=/ES/data/node1 -E path.logs=/ES/logs/node1

./elasticsearch -d  -E node.name=node-2 -E http.port=9201 -E transport.port=9301 -E path.data=/ES/data/node2 -E path.logs=/ES/logs/node2

./elasticsearch -d  -E node.name=node-3 -E http.port=9202 -E transport.port=9302 -E path.data=/ES/data/node3 -E path.logs=/ES/logs/node3

https://blog.youkuaiyun.com/jiankunking/article/details/65448030

https://blog.youkuaiyun.com/lixiaohai_918/article/details/89569611

查看插件命令:./elasticsearch-plugin list

下载插件命令:./elasticsearch-plugin install analysis-icu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值