Elasticsearch入门使用
#ES的部分原理
默认打分规则
默认相关性评分 (Relevance Score):
默认使用 BM25 算法(可以看作是 TF-IDF 的升级版)。它会综合考虑:
- 词频 (Term Frequency):关键词在文档中出现的次数。
- 逆文档频率 (Inverse Document Frequency):关键词在所有文档中的稀有程度。
- 字段长度 (Field Length):字段越短,匹配到的权重越高。
#ES的使用
##索引库操作
索引库就类似数据库表,mapping映射就类似表的结构。
我们要向es中存储数据,必须先创建“库”和“表”。
1. Mapping映射属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
- type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
keyword类型只能整体搜索,不支持搜索部分内容
- 数值:long、integer、short、byte、double、float、
- 布尔:boolean
- 日期:date
- 对象:object
- 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
- index:是否创建索引,默认为true
- analyzer:使用哪种分词器
- properties:该字段的子字段
例如下面的json文档:
1 | |
对应的每个字段映射(mapping):
- age:类型为 integer;参与搜索,因此需要index为true;无需分词器
- weight:类型为float;参与搜索,因此需要index为true;无需分词器
- isMarried:类型为boolean;参与搜索,因此需要index为true;无需分词器
- info:类型为字符串,需要分词,因此是text;参与搜索,因此需要index为true;分词器可以用ik_smart
- email:类型为字符串,但是不需要分词,因此是keyword;不参与搜索,因此需要index为false;无需分词器
- score:虽然是数组,但是我们只看元素的类型,类型为float;参与搜索,因此需要index为true;无需分词器
- name:类型为object,需要定义多个子属性- name.firstName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器
- name.lastName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器
2. 索引库的CRUD
CRUD简单描述:
- 创建索引库:PUT /索引库名
- 查询索引库:GET /索引库名
- 删除索引库:DELETE /索引库名
- 修改索引库(添加字段):PUT /索引库名/_mapping
这里统一使用Kibana编写DSL的方式来演示。
2.1 创建索引库和映射
基本语法:
- 请求方式:PUT
- 请求路径:/索引库名,可以自定义
- 请求参数:mapping映射
格式:
1 | |
示例:
1 | |
2.2 查询索引库
基本语法:
- 请求方式:GET
- 请求路径:/索引库名
- 请求参数:无
格式:
1 | |
2.3 修改索引库
这里的修改是只能增加新的字段到mapping中
倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这简直是灾难。因此索引库一旦创建,无法修改mapping。
虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。
语法说明:
1 | |
2.4 删除索引库
语法:
- 请求方式:DELETE
- 请求路径:/索引库名
- 请求参数:无
格式:
1 | |
文档操作
文档操作有哪些?
- 创建文档:POST /{索引库名}/_doc/文档id
- 查询文档:GET /{索引库名}/_doc/文档id
- 删除文档:DELETE /{索引库名}/_doc/文档id
- 修改文档:- 全量修改:PUT /{索引库名}/_doc/文档id
- 增量修改:POST /{索引库名}/_update/文档id { “doc”: {字段}}
1. 文档的CRUD
1.1 新增文档
语法:
1 | |
示例:
1 | |
1.2 查询文档
根据rest风格,新增是post,查询应该是get,不过查询一般都需要条件,这里我们把文档id带上。
语法:
1 | |
通过kibana查看数据:
1 | |
1.3 删除文档
删除使用DELETE请求,同样,需要根据id进行删除:
语法:
1 | |
示例:
1 | |
1.4 修改文档
修改有两种方式:
- 全量修改:直接覆盖原来的文档
- 增量修改:修改文档中的部分字段
1.4.1 全量修改
全量修改是覆盖原来的文档,其本质是:
- 根据指定的id删除文档
- 新增一个相同id的文档
注意:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。
语法:
1 | |
示例:
1 | |
1.4.2 增量修改
增量修改是只修改指定id匹配的文档中的部分字段。
语法:
1 | |
示例:
1 | |
DSL基本使用
第二部分:在 Kibana 中编写 DSL 的基本语法
Kibana 的 Dev Tools (开发工具) 提供了一个控制台,可以让你直接编写和发送 DSL 查询给 Elasticsearch。
1. 基本查询结构
一个典型的搜索请求结构如下:
1 | |
GET /your_index_name/_search: 请求方法是GET,路径是你的索引名加上_search端点。query: 最核心的部分,定义了你的搜索条件。from: 从第几条结果开始返回,用于分页(从0开始)。size: 返回多少条结果,用于分页。sort: 定义结果的排序规则。
2. 常用查询子句 (Query Clauses)
a. match_all: 匹配所有文档
最简单的查询,返回索引中的所有文档。
1 | |
b. match: 全文搜索
用于标准的全文搜索。它会先对查询字符串进行分词 (Analyze),然后去匹配分词后的词条。
- 场景: 搜索日志消息或文章内容。
1 | |
这个查询会找到 message 字段中包含 “connect”、”to” 或 “database” 的文档,并根据相关性评分排序。
c. multi_match: 多字段全文搜索
match 查询的升级版,允许你用一个关键词同时搜索多个字段。
- 场景: 在电商网站搜索“笔记本电脑”,希望同时匹配商品
title和description字段。
1 | |
d. match_phrase: 短语匹配
与 match 不同,它要求所有词条必须以相同的顺序紧邻出现。
- 场景: 搜索一个完整的句子或特定短语,例如 “真相只有一个”。
1 | |
e. term: 精确匹配
用于匹配未经分词的精确值。通常用于 keyword、integer、boolean 等类型的字段。
- 场景: 查找特定状态码、标签或ID。
1 | |
注意: 如果字段类型是 text,它会被分词。例如 “user-service” 可能会被分成 “user” 和 “service”。如果你想对整个 “user-service” 进行精确匹配,需要查询它的 .keyword 子字段(如果 mapping 中定义了的话)。
f. terms: 多个精确匹配 (OR)
term 的复数形式,匹配字段值在给定数组中的任意一个。
1 | |
g. range: 范围查询
用于数字、日期或字符串范围的查询。
gt: 大于 (greater than)gte: 大于等于 (greater than or equal to)lt: 小于 (less than)lte: 小于等于 (less than or equal to)
1 | |
h. bool: 组合查询 (布尔查询)
这是最强大、最常用的查询。它允许你将多个查询子句组合起来,实现复杂的逻辑。
must: AND 逻辑。所有子句都必须匹配,并且会计算相关性得分。should: OR 逻辑。至少有一个子句需要匹配。must_not: NOT 逻辑。所有子句都不能匹配。filter: AND 逻辑,但它在“过滤上下文”中执行。它不计算相关性得分,并且结果可以被缓存,因此性能更高。非常适合用于精确匹配的过滤条件。
1 | |
3. 进阶查询与相关性控制
以下查询子句提供了更精细的控制能力,用于优化搜索结果的相关性或处理特殊场景。
a. function_score: 自定义相关性得分
这是 Elasticsearch 的一个核心高级功能,它允许你修改一个查询产生的原始 _score。你可以引入业务相关的因子来影响最终排序。
- 场景:1. 新发布的文章应该有更高的排名。
- 点赞数、评论数越多的商品,排名越靠前。
- 距离用户当前位置越近的店铺,排名越靠前。
下面的例子中,我们在 match 查询的基础上,将文档的 likes (点赞数) 作为一个因子来提升最终得分。
1 | |
b. boosting: 降权查询
当你需要匹配一些内容,但希望其中某些特定条件会降低其相关性得分时使用。
- 场景: 搜索“苹果”,但希望包含“手机壳”的文档排名靠后一些。
1 | |
c. prefix 和 wildcard: 前缀与通配符查询
prefix: 查找以特定前缀开头的词条。wildcard: 使用*和?进行通配符匹配。- 场景: 用于搜索建议、自动补全或不确定的模式匹配。
1 | |
性能警告: 这两种查询(尤其是 wildcard)会消耗大量资源,因为它们需要扫描索引中的大量词条。除非必要,否则应避免在用户输入的查询中