1.重要概念
1.1索引(index)
一个索引就是一个拥有几分相似特征的文档的集合
,比如说,可以有一个商品数据的索引,一个订单数据的索引,还有一个用户数据的索引,一个索引由一个名字来标识(必须全部是小写字母)
, 我们要对这个索引中的文档进行索引、搜索、更新或者删除的时候,都需要用到这个名字。ES的索引可以看作是MySQL服务中的一个个的数据库
1.2映射(mapping)
映射(mapping)是定义一个文档和它所包含的字段如何被存储和索引的过程
, 在默认配置中,ES可以根据插入的数据自动创建mapping,也可以手动创建mapping(一般都是手动创建mapping),mapping中主要包括字段名、字段类型等。ES的mapping可以看作是MySQL服务中一个数据库中的一张表
注意
- 在 ES 7.0 之前,一个索引可拥有多个 Mapping
- 在 ES 7.0 之后,一个索引只对应一个 Mapping(即一个数据库中只有一张表)
1.3文档(Document)
文档是索引中存储的一条条数据,一个文档是一个可被索引的最小单元,ES中的文档采用了轻量级的JSON
格式数据来表示
ES中的文档可以看做是MySQL服务中一个数据库中的一张表的数据
2.基本使用
2.1索引相关操作
#添加索引
PUT /index_name
#查看ES中的所有索引 参数v表示显示所有索引时显示带上标题
GET _cat/indices?v
#删除指定索引
DELETE /index_name
注意:索引没有修改操作
2.2映射相关操作
2.2.1数据类型(常用)
字符串类型 keyword(不分词) text(分词)
数字类型 integer long
小数类型 float double
布尔类型 boolean
日期类型 date
2.2.2创建&查询映射
注意:ES没有修改和删除映射(mapping)的操作
想要删除或者修改映射,直接把索引index删除掉重新建立映射即可
PUT /index_name
{
//固定写法mappings
"mappings": {
//固定写法properties
"properties": {
//字段名
"id":{
//固定写法 type:数据类型
"type":"integer"
},
"title":{
"type":"keyword"
},
"price":{
"type":"double"
},
"created_at":{
"type": "date"
},
"description":{
"type": "text"
}
}
}
}
#查看某一个索引中的映射
GET /index_name/_mapping
2.3文档相关操作
2.3.1插入文档
插入文档**(手动指定_id)**
// 为索引中添加数据,指定_id
// 格式 POST /index_name/_doc/_id
POST /index_name/_doc/1
{
"id":1, //注意:这里的id与文档id(_id)不是一个东西,但是尽量与_id保持一致
"title":"布鲁克林篮网",
"price":233,
"created_at":"2001-10-20",
"description":"拥有KD-KI的一只超级球队"
}
插入文档 (自动生成_id)
//后面不加_id 自动生成的_id是一串uuid
POST /index_name/_doc/
{
//注意,手动生成_id,所以这里不在指定id的值
"title":"金州勇士",
"price":233,
"created_at":"2001-10-21",
"description":"拥有SC的一只超级球队"
}
2.3.2根据_id查询文档
注意:一定是_id,即文档id
GET /index_name/_doc/_id
2.3.3根据_id删除文档
注意:一定是_id,即文档id
DELETE /index_name/_doc/_id
2.3.4根据_id修改文档
方式一
//这种方式是先删除原始文档,然后插入,不会保留原始字段(不推荐)
PUT /index_name/_doc/_id
{
"price":233
}
方式二
POST /index_name/_doc/_id/_update
{
"doc":{
"xx":xxx
}
}
2.3.5批量操作_bulk
注意:如果有一条语句执行失败,不影响其他语句的执行
示例一:添加多条数据
POST /index_name/_doc/_bulk
{
"index":{
"_id":13}} //手动指定_id 下面的数据不允许格式化,只能写在一行
{
"id":13, "title":"休斯顿火箭","price":123,"created_at":"2001-10-21","description":"拥有SC的一只超级球队"}
{
"index":{
"_id":14}}
{
"id":14, "title":"底特律活塞","price":13, "created_at":"2003-10-21","description":"拥有SC的一只超级球队"}
示例二:增删改
#批量操作 -增删改
POST /products/_doc/_bulk
{
"index":{
"_id":15}} // index就是添加操作
{
"id":13, "title":"夏洛特黄蜂","price":123,"created_at":"2001-10-21","description":"拥有MJ的一只超级球队"}
{
"delete":{
"_id":13}} // delete删除
{
"update":{
"_id":1}} //update更新
{
"doc":{
"title":"OKC"}}
3.高级查询DSL
3.1简单查询
3.1.2查询所有
GET /index_name/_search
{
"query":{
"match_all": {
}
}
}
3.1.3term查询
- 除了
text
类型的字段(分词查询,只命中分词才能查询成功),其余字段在term查询时都不分词,即精确查询 - ES中默认使用的分词器为标准分词器,标准分词器对于英文内容,按照单词进行分词,对于中文单字分词
- term只支持查询一个字段。
GET /products/_search
{
"query": {
"term": {
"price": {
//字段名
"value": "xxx" //字段值 其他都是固定写法
}
}
}
}
3.1.4范围查询(range)
GET /products/_search
{
"query": {
"range": {
"price": {
//字段名
"gte": 10,
"lte": 232
}
}
}
}
3.1.5前缀查询(prefix)
基于关键词的前缀查询
keyword类型或者是text类型分完词后的关键字
GET /products/_search
{
"query": {
"prefix": {
"title": {
//字段名
"value": "夏洛特" //值
}
}
}
}
3.1.6通配符查询
基于关键词的通配符查询
keyword类型或者是text类型分完词后的关键字
GET /products/_search
{
"query": {
"wildcard": {
"title": {
//字段名
"value": "夏洛特*" // *表示匹配多个字符 ?表示一个一个字符
}
}
}
}
3.1.7多_id查询(ids)
GET /products/_search
{
"query": {
"ids": {
"values": [1, 2] //多个_id
}
}
}
3.1.8模糊查询
常用于keyword类型的字段
GET /products/_search
{
"query": {
"fuzzy": {
"title": "金州勇士"
}
}
}
注意:fuzzy模糊查询,最大的模糊错误必须在0-2之间
- 搜索关键词长度小于等于2时不允许存在模糊
- 搜索关键词长度为3-5时允许1次模糊
- 搜索关键词长度大于5时允许最大为2模糊
3.1.9布尔(组合)查询(bool)
bool关键字:用来组合多个条件实现复杂查询
- must 相当于
&&
同时成立 - should 相当于
||
成立一个即可 - must_not 相当于
!
不能满足任何一个
GET /products/_search
{
"query": {
"bool": {
"must": [ //必须匹配的条件
{
"term": {
"title": {
"value": "金州勇士"
}
}
},
{
"ids":{
"values": [1, 2]
}
}
],
"must_not": [ //必须不匹配的条件
{
"term": {
"title": {
"value": "金州勇士"
}
}
}
],
"should": [ //相当于匹配一个或多个即可
{
// ...条件
}
]
}
}
}
3.1.10多字段查询multi_match*
可以使多个字段根据同一个条件进行查询
注意:如果字段类型有分词(text类型的),将查询条件分词
之后进行查询该字段,如果该字段中没有分词(text类型)属性就会将查询条件作为整体进行查询
GET /products/_search
{
"query": {
"multi_match": {
"query": "库里",
"fields": ["title", "description"]
}
}
}
3.1.11query_string
查询字段类型是分词的就将查询条件分词后进行查询
,查询字段类型不分词的将查询条件不分词查询
GET /products/_search
{
"query": {
"query_string": {
"default_field": "description",
"query": "xxx"
}
}
}
3.1.12highlight高亮查询
对keyword和text类型都适用
GET /products/_search
{
"query": {
"term": {
"description": {
"value": "手"
}
}
},
"highlight": {
"pre_tags": ["<span style='color:red;'>"], //自定义前缀
"post_tags": ["</span>"], //自定义后缀
"fields": {
"*":{
}
}
}
}
3.1.13分页查询
size + from
GET /products/_search
{
"query": {
"match_all": {
}
},
"size": 2, //一页的记录数
"from": 0 //从哪条记录开始返回 (第一条数据从0开始)
}
3.1.14排序
GET /products/_search
{
"query": {
"match_all": {
}
},
"sort": [
{
"price": {
"order": "desc" //desc(默认降序) asc
}
}
]
}
3.1.15返回指定的字段_source
GET /products/_search
{
"query": {
"match_all": {
}
},
"_source": ["price","description"] //字段名
}
4.索引原理(倒排索引)
测试数据
索引
PUT /products/
{
"mappings": {
"properties": {
"title":{
"type":"keyword"
},
"price":{
"type":"double"
},
"description":{
"type": "text"
}
}
}
}
数据
POST /products/_doc/_bulk
{
"index":{
"_id":1}}
{
"title":"杜兰特","description":"雷勇篮","price":123.2}
{
"index":{
"_id":2}}
{
"title":"库里","description":"勇","price":23.2}
{
"index":{
"_id":3}}
{
"title":"詹姆斯","description":"骑热湖","price":13.4}
ES中的存储数据模型
倒排索引(Inverted Index)
,也叫反向索引,有反向索引必有正向索引。通俗的讲,正向索引就是通过key找value,反向索引则是通过value找key,ES底层在检索时底层使用的就是倒排索引
通过倒排索引搜索就非常快,因为索引中没有重复的关键字,并且每个单词都直接指向相关行
存储关键字出现的次数,以及数据的长度做一个相关性得分,次数越多,长度越短得分越高
5.IK分词器配置
关于安装IK分词器不再描述
使用
//分词器测试
POST /_analyze
{
"analyzer": "ik_max_word", //ik_max_word分词粒度细,ik_smart粒度粗
"text": "中华人民共和国歌" //需要分析的语句
}
// 创建映射,指定字段使用分词器
PUT /test
{
"mappings": {
"properties": {
"description":{
"type":"text",
"analyzer": "ik_max_word" //配置analyzer为ik_max_word,ik_smart粒度粗
}
}
}
}
//插入数据
POST /test/_doc/1
{
"description":"中华人民共和国"
}
//查询,人民 中华 共和国 等关键字都可以查询出来
GET /test/_search
{
"query": {
"term": {
"description": {
"value": "人民"
}
}
}
}
拓展词、停用词配置
IK支持自定义扩展词典
和停用词典
,
- 拓展词典就是有些词并不是关键词,但是也希望被ES用来作为检索的关键词,可以将这些词加入扩展词典
- 停用词典就是有些词是关键词,但是处于业务场景不想使用这些关键词被检索到,可以将这些词放入停用词典
定义扩展词典和停用词典可以修改IK分词器中config目录中IKAnalyzer.cfg.xml
这个文件
注意:自定义的词典,每一个单词占一行
6.过滤查询
过滤查询, 其实准确的来说,ES中的查询操作分为2种,查询(query)
和过滤(filter)
。查询即是之前提到的query查询
,它默认会计算每个返回文档的得分,然后根据得分排序,而过滤(filter)
只会筛选出符合的文档,并不计算得分,而且它可以缓存文档。所以单从性能考虑,过滤比查询更快,换句话说过滤适合在大范围筛选数据,而查询则适合精确匹配数据,一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据
。
GET /products/_search
{
"query": {
"bool": {
//filter必须配合bool使用
"must": [
{
"match_all": {
}
}
],
"filter": [ //注意,以下的过滤条件只能写一个
{
"term": {
//过滤出字段匹配的
"description": "雷",
},
"terms": {
//过滤出字段匹配多个的 (或)
"description": [
"雷",
"骑"
]
},
"range": {
//过滤出price在范围内的
"price": {
"gte": 10,
"lte": 20
}
},
"exists": {
//过滤出存在description字段的
"field": "description"
},
"ids": {
//过滤出id为xx xx的
"values": [
"1","2"
]
},
}
]
}
}
}