介绍

ElasticSearch是一个基于Lucene的 搜索引擎 以及 存储引擎。
它提供了一个 分布式 的 全文搜索引擎,其对外服务是基于RESTful web接口发布的。
Elasticsearch是用Java开发的应用,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。
设计用于云计算中,能够达到近实时搜索,稳定,可靠,快速,安装使用方便。
官网https://www.elastic.co

Github 使用Elasticsearch搜索20TB的数据,包括13亿的文件和1300亿行的代码”。
Github在2013年1月升级了他们的代码搜索,由solr转为Elasticsearch,
目前 集群规模为26个索引存储节点 和 8个客户端节点(负责处理搜索请求)。

ELK,分别是 ES, Logstash、Kibana 。
在发展过程中 新的成员Beats的加入, 就形成了 Elastic Stack (生态圈),
ES是 该 生态圈的 基石,Kibana提供可视化操作, Logstash和 Beats可以对数据进行收集

在国内,阿里巴巴、腾讯、滴滴、今日头条、饿了么、360安全、小米,vivo 等诸多知名公司都在使用Elasticsearch。

ElasticSearch VS Solr

Solr是 第一个 基于Lucene核心库功能完备的搜索引擎产品,诞生远早于Elasticsearchs
当 单纯的对 已有数据 进行搜索时,Solr更快。
当 实时建立索引时, Solr会产生IO阻塞,查询性能较差,ES具有明显优势。
大型互联网公司,实际生产环境测试,ES的 平均查询速度 是 Solr的 50倍。

版本特性

6.x新特性

  • Lucene 7.x
  • 新功能
  • 跨 集群 复制 (CCR)
  • 索引 生命周期 管理
  • SQL 的支持
  • 更 友好的 升级 及 数据 迁移
  • 在 主要版本 之间 的 迁移更为简化,体验升级
  • 全新的 基于操作的数据复制框架,可加快恢复数据
  • 性能优化
  • 有效 存储 稀疏字段 的 新方法 , 降低了存储成本
  • 在 索引 时进行 排序 , 可加快 排序的 查询 性能

7.x新特性

  • Lucene 8.0
  • 重大改动, 废除 单个 索引 下 多Type 的支持
  • Security 功能免费使用
  • 性能优化

8.x新特性

  • 重大改动, 彻底删除 Type
  • 默认开启安全配置
  • 性能优化

应用场景

  • 站内搜索
  • 日志管理、分析
  • 大数据分析
  • 应用性能检测
  • 机器学习

Docker 安装

  • ES 安装
docker pull elasticsearch:7.9.2docker run -d --name esearch \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" -e "discovery.type=single-node" \
-p 9200:9200 -p 9300:9300 \
elasticsearch:7.9.2# 进入容器 进行 跨域配置
docker exec -it esearch /bin/bash
vi config/elasticsearch.yml
# 加入以下信息:
http.cors.enabled: true
http.cors.allow-origin: "*"# 测试是否 成功启动: 访问elocalhost:9200 获得如下信息
{"name" : "bce8e8d3cddf","cluster_name" : "docker-cluster","cluster_uuid" : "chngjxFJTQStsI70tOn2HQ","version" : {"number" : "7.9.2","build_flavor" : "default","build_type" : "docker","build_hash" : "d34da0ea4a966c4e49417f2da2f244e3e97b4e6e","build_date" : "2020-09-23T00:45:33.626720Z","build_snapshot" : false,"lucene_version" : "8.6.2","minimum_wire_compatibility_version" : "6.8.0","minimum_index_compatibility_version" : "6.0.0-beta1"},"tagline" : "You Know, for Search"
}
  • ES可视化(ES-header)安装
docker pull mobz/elasticsearch-head:5-alpinedocker run -d --name es-head -p 9100:9100 mobz/elasticsearch-head:5-alpine# 测试是否 成功启动: 访问elocalhost:9100 得到 UI界面# ElasticSearch-head 在进行操作时 若不修改配置,会报 406错误码,
# 这里需要再对 ElasticSearch-head 进行 配置修改。
docker cp es-head:/usr/src/app/_site/vendor.js ./ # 因为该容器中没有vi,所以拷出来修改vim vendor.js
### 修改一下两部分:
part1: 第6886行 contentType:"application/x-www-form-urlencoded"改为:contentType:"application/json;charset=UTF-8"
par2: 第7573行 var inspectData = s.contentType === "application/x-www-form-urlencoded" &&改为:var inspectData = s.contentType === "application/json;charset=UTF-8" &&# 完成修改,将文件 复制回容器(即 覆盖掉同名文件)
docker cp ./vendor.js  es-head:/usr/src/app/_site# 重启容器
docker restart es-head# 浏览器在重新打开一下,别直接刷新,就可以操作ES了

重要概念

*_*倒排索引(反向索引)

全文检索: 通过一个程序 扫描文本 中的每一个单词, 针对单词 建立索引, 并保存 该单词在文本中的位置、以及出现的次数。
.
倒排索引:通过 搜索的关键字 在 倒排索引表 中找到 索引(id),然后再 通过 找到的索引 在 正排索引 中 找到数据。

例子:

  • 正排索引
id content
1001 my name is zhang san
1002 my name is li si
  • 倒排索引(在 正排索引 的基础上 通过 全文检索 创建出 倒排索引表)
key id
name 1001, 1002
zhang 1001

正排查找: id ===> value 通过 索引 找 数据
倒排查找: value ===> id 通过 关键字 找 索引, 然后在 通过索引 找 数据。

*_*ES文件目录结构

目录 描述
bin 脚本文件,包括 启动ES、安装插件、运行、统计数据等
config 配置文件目录
jdk java运行环境
data 默认的数据存放目录,包括节点、分片、索引、文档,生产环境需要修改
lib es依赖的java类库
logs 日志文件存放路径,生产环境需要修改
modules 包含所有的ES模块
plugins 已经安装的插件目录

*_*ES主配置文件 elasticsearch.yml

  • cluster.name

当前节点 所属 集群名称,
多个节点如果要组成同一个集群,那么集群名称一定要配置成相同。
默认值elasticsearch,生产环境建议根据ES集群的使用目的修改成合适的名字。

  • node.name

当前节点名称,
默认值当前节点部署所在机器的主机名,所以如果一台机器上要起多个ES节点的话,需要通过配置该属性明确指定不同的节点名称。

  • path.data

配置 数据存储目录,
比如索引数据等,默认值$ES_HOME/data,
生产环境下强烈建议部署到另外的安全目录,防止Es升级 导致数据被误删除。

  • path.logs

配置 日志存储目录,
比如运行日志和集群健康信息等,默认值$ES_HOME/logs,生产环境下强烈建议部署到另外的安全目录,
防止ES升级导致数据被误删除。

  • boostrap.memory_lock

ES启动时 是否进行 内存锁定, 默认 true。
ES对于 内存的需求比较大,一般 生产环境建议 配置大内存
如果内存不足,容易导致内存交换到磁盘,严重影响ES的性能。
所以默认在启动时进行相应大小内存的锁定,如果无法锁定则会启动失败。

在 config/jvm.option 配置文件中, Xms和 Xmx设置成一样, 但是不要超所 主机内存的 50%

  • network.host

配置 可以访问 当前节点的 主机。
默认值为 仅本机访问,可以配置为0.0.0.0,表示 所有主机 均可访问。

  • http.port

对外提供服务的端口,默认是 9200

  • discovery.seed_hosts

配置 参与集群 节点 发现过程 的 主机列表,
说白一点就是 集群中 所有节点 所在的主机列表,可以是IP、域名。

  • cluster.initial_master_nodes

配置 ES集群 初始化是 参与 master 选举的 节点名称列表,必须和 node.name配置一致。
ES集群首次 构建完成后,应该将 集群中所有节点 的配置文件 中的 clusterinitial_master_nodes配置项移除,
重启集群 或者 将新节点加入某个已存在的集群时 切记 不要设置该配置项。

*_*ES两个重要的端口

  • 9200 是客户端 访问 ES服务端的 端口;
  • 9300 是 ES 节点间 交互的 端口。

*_*分布式概念

cluster

cluster集群。ElasticSearch集群由 一 或 多个 节点组成,
其中有一个主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。
ElasticSearch的一个概念就是 去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,
因为从外部看ElasticSearch集群,在逻辑上是个整体,你与集群中的任何一个节点通信和与整个ElasticSearch集群通信是等价的。
也就是说,主节点的存在不会产生单点安全隐患、并发访问瓶颈等问题。

shards

primary shard:代表索引的主分片,ElasticSearch可以把一个完整的索引分成多个primary shard,
这样的好处是可以把一个大的索引拆分成多个分片,分布存储在不同的ElasticSearch节点上,
从而形成分布式存储,并为搜索访问提供分布式服务,提高并发处理能力。
primary shard的 数量 只能在索引创建时指定,并且索引创建后不能再更改primary shard数量 (重新分片需要重新定义分片规则)。
primary shard的 数量 es5.x之后默认为5,es7.x默认为1

replicas

replica shard:代表索引主分片的副本,ElasticSearch可以设置多个replica shard。可取值为0~n,默认为1。
replica shard的作用:

  1. 是提高系统的容错性,当某个节点某个primary shard损坏或丢失时可以从副本中恢复。
  2. 是提高ElasticSearch的查询效率,ElasticSearch会自动对搜索请求进行负载均衡,将并发的搜索请求发送给合适的节点,增强并发能力

*_*和 关系性数据库 概念类比

mysql 数据库 数据表 记录 字段
ES Index(索引) Type(类型) Document(文档) Field

注意:在8.x之后 ,Type被砍掉以后,Index 既是 数据库,又是 数据表。

*_*插件安装

这里以安装 分词器 为例,至于什么是 分词器,下面会进行解释说明。

在线安装

# 查看已经安装的插件
bin/elasticsearch-plugin list# 安装 analysis-icu 插件, 重启ES生效
bin/elasticsearch-plugin install analysis-icu# 卸载插件,重启ES生效
bin/elasticsearch-plugin remove analysis-icu

离线安装

下载 相应的插件 到本地, 解压后,手动上传到 ES的 plugins目录,然后重启 ES就可以了。

*_*分词器

前面提到的 全文检索 就是 通过 分词器 来完成的,
分词器 是对 文件 进行 字词 划分的 唯一单位。
ES默认的分词器 是 standard 对中文不是太友好,分词的依据 就是将 单字 拆分。
ik中文分词器 是对中文 比较有好的 。

# 测试分词器 的分词 效果
POST 请求/_analyze 请求路径请求体:
{"analyzer": "icu_analyzer","text":"我爱你中国"
}

ik分词器的测试

一、粗粒度-少分次:一般用于 文章名称、人的姓名 等 不希望进一步拆分 的信息
POST  /_analyze
{"analyzer": "ik_smart","text":"我爱你中国"
}分词效果: 我爱你中国 ===》 我爱你中国二、细粒度-分多次:
{"analyzer": "ik_max_word","text":"我爱你中国"
}分词效果: 我爱你中国 ===》 我爱你中国、我爱你、爱你、中国

在创建 索引时 可以 指定 分词器

{"settings":{"index": {"analysis.analyzer.default.type": "ik_max_word"}}
}

*_*相关性 和 相关性计算——打分

这个地方 对 后面的 布尔查询 的算分 有理解上的帮助。
.
搜索行为 是 用户 和 搜索引擎 的交互, 用户往往关心 的是 搜索结果 的 相关性。
搜索的相关性算分, 描述的指标是 返回的文档 和 关键字的 匹配程度。
ES 会对 每一个 匹配查询 的结果 进行 算分 _score. 打分 的本质是 排序, 把 符合预期的 排在 前面。
ES 5 之前 算分的算法 使用的是 TF-IDF, 之后使用的是 BM 25, 是对 前者的 优化。

  • TF-IDF

是一种 用于 信息检索 和 数据挖掘 的 常用 加权技术。
是 被公认 的 信息检索 领域 的 最重要的 发明。
其 公式的 三个 决断 算分 结果 的 变量如下:

  • 词频TF: 对于 某一条 数据而言, 检索词 出现的频率越高, 相关性越高。
  • 逆向文本频率IDF: 对于 多条 数据而言, 检索词 出现的频率越低, 相关性越高。举例:
    我们 搜索: ES java, 假如一共有10条数据, 每条数据都有 ES信息, 只有 前两条 有java信息, 明显 这里 ES的频率 高于 java, 但是 java的 相关性 要 大于 ES。
  • 字段长度归一值: 为什么 字段长度越短 权重越高,因为 字段越长 越有出现 信息冗余的可能,每个人组织语言的能力都是有一定缺陷的,话说的越多 废话 就越多。
  • BM25

BM25 优化 TF-IDF 算法, 减少 分数计算的 资源损耗。
词频不断增加时, TF-IDF 算法 的打出的 分数 是 无限增加, 而 BM25是趋近于一个 数值。

索引index

一个索引 就是一个 拥有 几分相似特征 的文档的集合。
索引的命名 必须 全部是 小写字母, 不能以 下划线 开头。

索引 主要有三个大属性(部分)组成:

  • aliases 别名
  • mappings 文档映射
    数据字段 和 字段类型 的映射, 创建索引的时候不设置,添加数据后 会自动设置,当然也可以手动设置。
  • settings 设置
    设置 索引 相关的一些属性

mappings 文档映射

Mapping 类似 数据库 中的 schema的定义,作用如下:

  • 定义索引中的 字段名称
  • 定义字段的 数据类型,例如字符串,数字,布尔等
  • 字段,倒排索引 的 相关配置(AnalyzedorNotAnalyzed,Analyzer)

Mapping映射 分为 动态 和 静态:

  • 动态
    在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。
    而Elasticsearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识.
  • 静态
    事先 手动 定义好映射。

动态映射 的 类型识别机制

JSON类型 ES类型
字符串 1- 匹配日期格式,设置为Date 2- 配置数据设置为float或long,默认关闭 3- 设置为Text,并且增加keyword字段
布尔值 boolean
浮点数 float
整数 long
对象 object
数组 由第一个非空元素决定
空值 忽略

Mapping生成之后,后期修改会怎么样?

  • 新增字段
  • dynamic设为true时,一旦有新增字段的文档写入,Mapping也同时被更新
  • dynamic设为false,Mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在source中
  • dynamic设置成strict(严格控制策略),文档写入失败,抛出异常
// dynamic 设置为 true | false:
PUT /wtt/_mapping
{"dynamic": true
}
  • 修改字段

倒排索引表 一旦生成, 就不允许 修改,原因是 修改字段的数据类型 会导致 已被索引的 数据 无法被 搜索。
如果 就是任性 的想该字段,那么就 重建索引 呗。

// 重建索引
-- step1: 新建一个 静态索引,把之前的 索引的 数据 导入新的 索引中
POST /_reindex
{"source": {"index":"wtt"},"dest":{"index":"wtt2"}
}-- step2: 删出原来的索引
DELETE /wtt-- step3: 给新索引 起一个 老索引 的 别名
PUT /wtt2/_alias/wtt

让某个字段 不被 索引

PUT /wtt
{"mapping":{"properties": {"address": {"type":"text","index":false  # address  不再被 索引了}}}
}

控制 倒排索引 记录的内容

记录内容: doc id(文档id) term frequency(词频) term position(位置) character offects(关联、影响)
docs y n n n
freqs y y n n
positions y y y n
offsets y y y y

说明: text类型 默认记录 positions, 其他默认记为 docs。

PUT /wtt
{"mappings": {"name": {"type": "text","index_options": "offsets" // 这里指定 记录内容}}
}

对Null值 的 搜索

只有 keyword 类型 支持 null_value 的设置。

PUT /wtt
{"mappings": {"name": {"type": "keyword","null_value": "NULL" // 这样一来,该字段就可以 通过null值 搜索了}}
}

常见操作

  • 创建
# PUT: 创建 shopping 索引
http://127.0.0.1:9200/shopping# 指定 分片数 和 副本数
PUT /shopping
{"settings": {"number_of_shards": 3,  //分片"number_of_replicas": 2 //副本}
}
  • 查看
# GET: 查看 指定 索引
http://127.0.0.1:9200/shopping# 查看 索引 是否存在
HEAD    /shopping# GET: 查看 全部 索引
http://127.0.0.1:9200/_cat/indices?v
  • 删除
# DELETE
http://127.0.0.1:9200/shopping
  • 编辑
PUT /shopping/_settings
{"index": {"number_of_replicas": 3 //副本}
}

文档

ES 是面向 文档的, 文档(不是 字段) 是 可搜索数据的 最小单位。
文档 会被 序列化为 JSON格式,保存在 ES中。
每一个 文档 都有一个 唯一 ID,可以 自动生成 也可以 手动指定。

文档元数据

  • _index:文档所属的 索引 名。
  • _type:文档 所属的 类名
  • _id:文档的 唯一id
  • _source:文档的原始 json数据
  • version:文档的版本号, 修改、删除 操作 会使得 version 自增1
  • seq_no : 修改、删除 操作 会使得 version 自增1
  • primary_term :是 纪元数据,每次 分区选举 都会 自增1。即 记录朝代的更替。
# seq_no 和 primary_term 属性 主要用来 并发场景下 修改文档, 是对 version 的优化
POST /wtt/_doc/11?if_seq_no=21&if_primary_term=6
{"name":"tom"
}-- 说明:
只有id为11的文档 满足 seq_no==21   且 primary_term == 6
才会 进行 数据加入 的操作。

相关操作

创建

  • POST

通过 指定ID的方式 添加文档,

  • ID不存在 :创建新的文档
  • ID已存在 :先删除 原有文档,再 创建新的文档, version会增加。即 数据覆盖
# POST
http://127.0.0.1:9200/shopping/_doc
# 请求体
{"title":"小米","category":"米","images":"http://***.png","price":123.01
}# 返回 的 _id 字段 是ES随机为该条记录生成的 文档id。
# 可以通过这个文档id来查询 该条记录的文档信息。### 创建 指定id的文档 ###
# POST: 指定id为1001
http://127.0.0.1:9200/shopping/_doc/1001
  • PUT

PUT也可以用来 添加数据,但是 和 POST有区别:

  • POST
    post本意是添加数据,所以可以不用 指定 文档id,如果制定了 文档id,那么es就会判断该 id是否存在,
    存在则 更新操作,不存在 则算是 添加数据的操作。
  • PUT

  • 本意是 更新数据,所以 必须 指定 文档id。

  • 查看

# GET: 查看 指定id 文档
http://127.0.0.1:9200/shopping/_doc/1001# GET: 查看 全部 文档
http://127.0.0.1:9200/shopping/_search
  • CREST

该种创建数据的方式 主要是为了 添加数据 不小心 变成了 数据覆盖 了,
所以 如果ID已经存在,那么就会 操作失败。

PUT /shopping/_create/11
{"title":"小米","category":"米","images":"http://***.png","price":123.01
}

编辑

  • 全量更新

删除原有文档,创建新的文档

  • 部分更新

可以更新 部分字段, 是传统意义上的更新

# PUT: 全量更新
http://127.0.0.1:9200/shopping/_doc/1001
# 请求体中 含有 修改之后的信息# POST: 部分更新
http://127.0.0.1:9200/shopping/_update/1001
# 请求体
{"doc":{"title":"华为"}
}
  • 条件更新
POST /shopping/_update_by_query
{"query": {"match": {"title":"小米手机"}},"script":{"source": "ctx,_source.age = 30"}
}

删除

# DELETE:
http://127.0.0.1:9200/shopping/_doc/11

查询

  • 根据id
GET /shopping/_doc/11
  • 条件查询

ES 提供 两种 条件查询方式:

  • 条件数据 放在 query 中, 作为 URL的一部分
  • 条件数据 放在 request body 中,官方推荐该种, 易读性强,后面会重点讲解
##### 放在 query 中
# 使用 q 指定查询字符串
# 搜索 年龄 在 15到35之间的, 跳过0个开始搜索,一共搜索10个数据
GET /shopping/_doc/_search?q=age[15 TO 35]&from=0&size10##### 放在 request body 中
# GET
http://127.0.0.1:9200/shopping/_search
# 请求体
{"query": {"match": { //模糊 查词 匹配查询"title": "小米手机" //查询字段 和 查询字段值}},// 获取指定列的数据"_source": [ "title","price"],// 排序"sort": {  "price": {"order": "desc" // 降序}},// 分页"from": 1, // 从第1条开始查 "size": 10 // 获取10条数据
}

Request Body 文档查询方式

接下来 重点 讲解 官方建议 通过 request body 的方式进行 查询,因为这种方式 可以 定义 更加易读的 json格式。
但在此之前 要 先讲一下 相关原理

ES检索原理

  • 索引的原理

索引 是加速数据查询的 重要手段,其 核心原理 就是 通过不不断的 缩小 想要获取数据的 范围, 来 筛选出 最终想要的结果。

  • 磁盘IO 和 预读

磁盘IO 是程序设计中 非常 昂贵的 操作, 也是 影响 程序性能 的重要因素
因此 应当 避免过多的 磁盘IO,最直接有效的方式 就是 利用 内存。
局部性原理 告诉我们,当计算机访问一个地址的数据的时候,与其相邻的地址也会很快被访问到。
因此 预读 就是 发生一次 IO时, 不仅仅是 度全当前的 磁盘数据, 而且把相邻地址的数据也读取到内存中。

上图主要为了说明两点:

  • 磁盘IO的空间关系
  • 查询 数据的结果 和 词项-字典 有直接的关系, 而 词项-字典 的存储内容 有 分词器 直接指定。
    所以 查询数据的结果 和 分词器 息息相关

常用查询操作

全量查询 match_all

使用match_all, 默认 返回 10 条数据。
其原因是: 如果 全部数据有几十万条,一次性都查出来的话 内存一下子会 盛放不了 导致 宕机。

GET /wtt/_search
{"query":{"match_all": {}}
}

分页查询

  • size: limit
  • from:offset
GET /wtt/_search
{"query":{"match_all": {}}"size": 10,"from": 0
}

注意:
size 不可以无线增加,size 默认 小于等于 10000,超过这个数会报错。
如果需要可以 手动修改默认值,如下

PUT /wtt/_settings
{"index.max_result_window": "20000"
}

但是数据量需求过大的时候, 不推荐 修改上述配置,而是采用 scroll api,因为 更高效。

分页查询 Scroll

改动 index.max_result_window 的大小,只能解决一时的问题,当 数据持续增加时,
在 查询 全量数据时,若超过 手动指定的数据 还是会报错。
最佳的方式 还是采用 scroll api

# 查询命令中 新增 scroll=3m,说明采用 游标查询, 保持游标查询窗口 3分钟,
# 即游标变量 中存储的地址信息 在3分钟后 被 垃圾回收机制 回收掉
# 实际使用中,为了减少 游标的查询次数,可以将 size 适当增加,例如500---2000
GET /wtt/_search?scroll=3m
{"query": {"match_all": {}},"size": 10
}
-- 查询结果 除了放回 前10条记录,还返回一个 游标ID值 _scroll_id# 下一次查询, 只需要带上 上一次的 游标ID 就可以了, ES就知道 怎么查,查什么,查多少了
GET /_search/scroll
{"scroll": "2m","scroll_id": "jfldJLJfldjfLJDfjldlFJljf453JLFJfjdljl"
}
-- 多次根据 scroll_id游标查询,知道没有 数据的返回 则 结束查询。
-- 全量数据 用 游标查询 的好处:高效安全、限制单次对内存的 损耗。

排序 和 指定要返回的部分字段

GET /wtt/_search
{"query": {"match_all": {}},"sort": [{"age": "desc"}],"_source": ["name", "age"]
}

通过 降低相关性 实现 更复杂 的 排序 场景

我们知道,ES默认返回文档的 顺序 如果没有 sort的干预 是采用 打分排序的,
所以 可以 通过 调整 权重 来干预打分机制,
在 打分时, negative 部分 的 query 会乘以 negative_boost的值,
negative_boost 的取值范围: 0—1

-- 例如: 我们搜索 苹果 关键字时, 我们希望 苹果手机  排在前面, 而 苹果水果 排在后面
GET /wtt/_search
{"query": {"boosting": {"positive":{ // 积极"match": { "content": "apple" }},"positive":{ // 消极, 该部分 会乘以 negative_boost的值"match": { "content": "pie" }},"negative_boost": 0.2}}
}

分词查询 match

match 在匹配时 会对 所查找的 关键字 进行分词, 然后 再 按 关键字 分词 进行匹配查找。
match支持以下参数:

  • query: 指定 匹配的值
  • operator: 匹配类型
  • and : 关键字 的 分词 都要 匹配上
  • or : 关键字 的 分词 至少有一个 能匹配上
  • minmum_should_match: 最低匹配度, 配合 or的情况,因为or默认是1个,该配置 指定最少匹配的关键词数
GET /wtt/_search
{"query": {"match":{"film_name": {"query": "你好李焕英","operator": "and"}}}
}

短语查询 match_phrase

match_phrase查询分析文本 并 根据 分析的文本 创建一个 短语查询。
match_phrase 也会将 管理子 分词, 但是匹配机制 更严格:

  • 分词结果 必须 都被匹配上。
  • 分词结果 的匹配 顺序必须相同。
  • 分词结果 的匹配 默认都是连续的。
-- 举例说明: 现ES存储一条文档, 字段address的内容是 “广州白云山” ===分词的顺序、结果为===>广州、白云山、白云-- 查找1
GET /wtt/_search
{"query": {"match_phrase": {"address": "广州白云山"}}
}-- 查找2
GET /wtt/_search
{"query": {"match_phrase": {"address": "广州白云"}}
}--- 结果分析:
查找1 命中了数据, 查找2 没用命中一条数据。
这只因为 查找2的 搜索词被  拆成了 广州、白云, 文档库中的 分词是: 广州、白云山、白云
虽然 满足 1、全命中 2、顺序相同
但是不满足 3、连续, 明显 文档的分词 广州 和 白云 之前还隔着 一个 白云山。  -- 解决方法:
通过 slop 参数 告诉 match_phrase 中间 隔 几个词 也可以认为是连续的
GET /wtt/_search
{"query": {"match_phrase": {"address":  {"query": "广州白云","slop": 1  // 这样一来 就能匹配上了}}}
}

多字段 multi_match

GET /wtt/_search
{"query": {"multi_match":{"query": "你好","fields": ["address", "name"]  // 这 俩字段 只要能 匹配上 你好 的 文档 都可以被命中}}
}

query_string

允许我们在单个查询 字符串 中指定 AND | OR | NOT 条件,
和 multi_match 一样 支持多字段搜索。
和 match 类型,但是match 需要指定 字段名, query_string在所有字段中搜索,范围更广。

注意:

  • 查询的字段 使用分词, 就将 查询条件 分词查询。
  • 查询的字段 未使用分词, 就将 查询条件 不分词查询。
  • 不指定 字段 查询
GET /wtt/_search
{"query": {"query_string": {"query":"张三 OR 山东省"}}
}
  • 指定 单个字段 查询
GET /wtt/_search
{"query": {"query_string": {"default_field": "name""query":"张三 OR 李四"}}
}
  • 指定 多个字段 查询
GET /wtt/_search
{"query": {"query_string": {"fields": ["name", "sex"]"query":"张三 OR (李四 AND 女)"}}
}

关键字查询 Term

term 是用来 精准查询 的,还可以用来 查询 没有被 进行分词的 数据类型。
term 是表达语义 的最小单位。
match 匹配时 会对 关键词 进行 分词处理,然后在 进行 分词匹配。
而 term 不做 分词处理, 会直接对 关键字 进行 匹配 。
因此 模糊查询的 时候 常用 match, 精准匹配 的时候 常用 term。

  • 类型的分词说明

在ES中, keyword、date、integer、long、double、boolean、ip 这些类型不会 分词,
text类型 会分词。

-- 查找1
GET /wtt/_search
{"query": {"term": {"address": {"value": "山东省临沂市"}}}
}-- 查找2
GET /wtt/_search
{"query": {"term": {"address.keyword": {"value": "山东省临沂市"}}}
}--- 结果说明:
查找1 未命中数据, 查找2 命中数据--- 原因解释:
term查询,不会对 山东省临沂市 进行分词, 而 address 的 text 类型 会对 山东省临沂市 ===分词为===> 山东省、临沂市。
所以 待配的 词库中 没有 能和 山东省临沂市 匹配上的。而 address 的 keyword 类型 不会对 山东省临沂市 进行分词为, 所以可以命中数据。  所以 精准匹配的 时候 最好使用 keyword 类型
  • 性能优化

精准匹配这一块 是有个 值得 优化的点的,
每次 查询数据 es对于每一个 找到的 结果数据 都有一个分值 计算, 该分值 体现了 数据的匹配度。
在 精准查询 下, 这个 分值 没有多大意义, 所以去掉 算分动作(毕竟有资源损耗)可以优化性能。
实现机制:

将query 转成 filter 就可以 去掉 算分动作 , filter 可以有效利用 缓存。

GET /wtt/_search
{"query": {"contant_score": {"filter":{"term": {"address.keyword": "山东省临沂市"}}}}
}
  • 精准查询 用的最多的 常见

对bool、日期、数字、结构化的文本 都可以 利用 term 做 精准匹配。

GET /wtt/_search
{"query": {"term": {"age": {"value": 18}}}
}
  • term 多值字段(数组)的处理

对于 多值字段, term 查询 是包含, 而不是 等于

-- 假设现在有两个文档:
{"name": "tom","hobby": ["篮球", "足球"]  // 多值字段
}{"name": "cat","hobby": ["游泳", "篮球"]  // 多值字段
}-- 多值字段的查询
GET /wtt/_search
{"query": {"term": {"hobby.keyword": {"value": "篮球"  // 可以命中以上 两条数据}}}
}

prefix 前缀搜索

它 不会 对 关键字 进行分词, 查询的内容 就是 查找的 前缀。
它的原理: 遍历所有的 倒排索引 , 比较每个 term(基本单位)的前缀 是否能匹配上 。
它的行为 和 过滤器 很像, 区别在于 过滤器 是可以被缓存的, 它不行。

GET /wtt/_search
{"query": {"prefix": {"address": {"value": "山"}}}
}

wildcard 通配符查询

其 工作原理 和 prefix 相同,只不过 它能支持 更为复杂的 模式

GET /wtt/_search
{"query": {"wildcard": {"address": {"value": "*东*"  // 可以命中 山东省}}}
}

范围查询 range

支持的 范围描述 关键字有:

  • gte:大于等于
  • lte:小于等于
  • gt:大于
  • lt:小于
    -now :当前时间
  • 数值范围
GET /wtt/_search
{"query": {"range": {"age": {"gte":15,"lte":35}}}
}
  • 日期范围
GET /wtt/_search
{"query": {"range": {"dates": {"gte":"now-2y", //大于 两年前"lte":"now-10m" //小于 10个月前 }}}
}

多id查询

ids 关键字: 置为 数组类型, 用来 根据 一组 id 获取 对应的 多个 文档。

GET /wtt/_search
{"query": {"ids": {"values": [1,2,3]}}
}

模糊查询 fuzzy

在实际中,我们又是 会 打错字,从而导致 搜索不到。
在ES中,使用 fuzziness 属性 来进行 模糊查询,来解决上述问题。

fuzzy 查询 会用到 两个很重要的参数:

  • fuzziness: 输入的 关键字 通过几次 可以转换为 ES中 对应的 字段
  • 操作是指: 新增、删除、修改,每次操作记为 1步
  • 该参数值 默认为 0, 即 不开启 模糊查询。
  • prefix_length: 表示 关键字 和 ES中字段 的开头前 几个 字符必须完全匹配,不可出错
  • 默认值为0
  • 加大该值 可以 提高 匹配准确率
GET /wtt/_search
{"query": {"fuzzy": {"address": {"value": "山冬省"  "fuzziness": 1 // 可以命中 山东省}}}
}

注意: 摸出查询 的 最大模糊错误 必须在 0–2之间

关键字长度 是否允许存在模糊 模糊次数
2 不允许
3-5 允许 1
大于5 允许 2

高亮查询

hightlight 关键字 可以让 符合条件的 数据 高亮。
其相关属性:

  • pre_tags 前缀标签
  • post_tags 后缀标签
  • tags_schema 设置为 styled 可以使用内置高亮样式
  • require_field_match 多字段 高亮 需要设置为 false
GET /wtt/_search
{"query": {"fuzzy": {"address": {"value": "山冬省"  "fuzziness": 1 }}},"highlight": {"fields": {"*"{}  // 此时的高亮字段 就是 查询匹配字段  address}}
}-- 可以自定义 高亮样式 且 多字段 高亮
GET /wtt/_search
{"query": {"fuzzy": {"address": {"value": "山冬省"  "fuzziness": 1 }}},"highlight": {"pre_tags": ["<h1 style='color:red'>"],"post_tags": ["</h1>"],"fields": {"name":{} ,  // 也可以是 没有 查找匹配的 文档字段"address":{} }}
}

布尔查询 bool query

一个 bool 查询 是 一个 or 多个 查询子句 的 组合, 总共包括 4 种句子。
其中 2 种 会影响 打分, 2种 不影响 打分。

子句类型 相当于 匹配说明 是否贡献算分
must && 必须匹配 贡献
should || 选择性匹配 贡献
must_not 必须不能匹配
filter 必须匹配

在ES中, 有 Query 和 Filter 两种不同的 Context

  • Query Context: 相关性 算法
  • Filter Context: 不需要算法, 可以利用 cache, 获得 更好的性能

子查询 可以 任意顺序出现,
可以 嵌套多个查询,

GET /wtt/_search
{"query": {"bool": {"must": [{ "term": { "sex": { "value": 1 } }},{ "match": { "address": "山东临沂" }}], "shuold": [{ "term": { "sex": { "value": 1 } }},{ "match": { "address": "山东临沂" }}],"minimum_should_match": 1 // shuold 下的俩个条件 至少满足 1 个}}
}

演示一下 bool 嵌套

GET /wtt/_search
{"query": {"bool": { // 第一层"must": [{ "bool": { // 第二层"must": [{ "term": { "sex": { "value": 1 } }},{ "match": { "address": "山东临沂" }}]}}]}}
}

聚合查询

{"aggs":{ // 聚合操作"price_group":{ // 名称,自定义"avg":{ // 平均值"field":"price" // 分组字段}}}
}

ElasticSearch 哪里不会点哪里相关推荐

  1. Elasticsearch学习之路(一)

    一.前序 1.1正向索引和倒排索引 ** 正向索引通常用于数据库中,在搜索引擎领域使用的最多的就是倒排索引 ** 通过例子表示: 我爱编程, 我爱编程,我是小码农 1.1.1 正向索引 假设我们使用m ...

  2. 2021年大数据ELK(二十五):添加Elasticsearch数据源

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 添加Elasticsearch数据源 一.Kibana索引模式 添加Elast ...

  3. 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 使用FileBeat采集Kafka日志到Elasticsearch 一.需求分 ...

  4. 2021年大数据ELK(十七):Elasticsearch SQL 订单统计分析案例

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 订单统计分析案例 一.案例介绍 二.创建索引 三.导入测试数据 四.统计不同支 ...

  5. 2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 职位查询案例 一.查询职位索引库中的一条数据 二.将SQL转换为DSL 三.职 ...

  6. 2021年大数据ELK(十五):Elasticsearch SQL简单介绍

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch SQL简单介绍 一.SQL与Elasticsear ...

  7. 2021年大数据ELK(十三):Elasticsearch编程(添加职位数据)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch编程 一.添加职位数据 1.初始化客户端连接 2.实 ...

  8. 2021年大数据ELK(十二):Elasticsearch编程(环境准备)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch编程 一.环境准备 1.准备IDEA项目结构 2.准 ...

  9. 2021年大数据ELK(十一):Elasticsearch架构原理

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 Elasticsearch架构原理 一.Elasticsearch的节点类型 ...

  10. 2021年大数据ELK(八):Elasticsearch安装IK分词器插件

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 安装IK分词器 一.下载Elasticsearch IK分词器 ...

最新文章

  1. myeclipse java可视化_使用MyEclipse可视化开发Hibernate实例
  2. java 画笔粗细_用JAVA做个画笔,有画笔和橡皮功能就行。越简单越好
  3. 基于软件开发对嵌入式开发的思考
  4. 小程序 图片上传php后台,微信小程序图片选择、上传到服务器、预览(PHP)实现实例...
  5. 【Codeforces Round #438 C】 Qualification Rounds
  6. 坦克乘员协同训练模拟系统
  7. ARPG游戏打击感相关的技术简单总结
  8. mapper.xml 的配置
  9. Clark与Park变换详解
  10. 微信小程序之发送表情和文字和语音之php
  11. 转:7招,教你在工作中高效做笔记
  12. python---关于集合
  13. 【方块消除】(附加工程)
  14. vue中Echarts地图组件+城市json文件
  15. 2014年全球手游市场发展的六大趋势
  16. 论文笔记:Federated Graph Neural Networks: Overview, Techniques and Challenges
  17. android tween动画平移怎么设置时间,android Tween Animation属性设置方法实例
  18. 中兴JAVA直板手机_中国移动定制中兴直板3G手机U210图赏
  19. Android系统手机USB驱动程序安装教程
  20. Android 自定义Dialog实现(二)

热门文章

  1. 京东商品详情数据接口(APP端,H5端),实时了解商品价格走势,接口代码教程
  2. 西南大学网络作业答案计算机,西南大学网络教育2018[9124]《计算机图像处理基础》作业标准答案.docx...
  3. java中curr是什么意思_curr.是什么意思
  4. SSL 3.0曝出Poodle漏洞的解决方案
  5. [055] SSL 3.0曝出Poodle漏洞的解决方案-----开发者篇
  6. 【12306刷票必备!!!】12306订票助手----无所不能的谷歌浏览器chrome插件
  7. gitlab服务: kex_exchange_identification: Connection closed by remote host
  8. 年薪百万,到手能拿到多少钱?
  9. 移植MT7620A+MT7610E驱动到Openwrt trunk(Linux Kernel 3.14.18)(续:MT7620A)
  10. Windows服务器应该如何保持长时间连接不断开。