ElasticSearch从入门到精通

es是文档数据库

es8.x默认开启了security,无法0配置启动

配置:

cluster.name: 机器名称,同一集群名称相同,用来发现集群节点

Node.name: 节点名称,同一集群节点名称是唯一的,对应一个es实例

path.data:

path.log:

network.host: es对外提供服务的IP地址,默认会绑定本地回环地址

http.port: 对外提供服务的端口号,默认9200,如果已绑定会自动递增

transport.port: 节点间通信的端口号,默认9300,集群使用

首次启动之后,es会自动在yml配置文件中添加xpack securiy的配置,将它置为false,重新启动,才可以localhost:9200访问,返回Json,说明成功启动,json中有主机名、集群名

开发模式和生产模式:

开发模式:没有引导检查(启动时检查配置),默认是开发模式

生产模式:有引导检查,检查配置更严格

如果配置了非本地回环地址,能和其它节点形成集群,则进入生产模式

安装启动es

es不能root启动

useradd es

passwd es

chown -R es:es /home/es

./elasticesearch -d 后台启动,8.x启动后会打印密码(可以通过reset修改)、CA证书密钥、kibana访问token,需要保存。

启动后要通过https访问,账号是elastic

yml配置中将xpack.enable=false,则可以用http访问

集群

集群加入节点:在原集群的一个节点执行es-create-enrollment-token -s node创建token,在新节点执行这个token(bin/elasticsearch --enrollment-token )

单项目多节点:单个es目录,使用./es -Epath.data= -Epath.logs= -Enode.name= -Ecluster.name=

多项目多节点:多个es目录,占磁盘空间,独立配置,方便用配置文件修改,使用一个外部命令执行多个节点的启动,localhost:9200/_cat/nodes?v查看集群节点

安装启动kibana

如果修改了es端口号,需要修改kibana的es访问配置,es.hosts

启动后,访问localhost:5601,设置es的kibana token

进入devtools,可以执行查询脚本

学习方法

有所学有所不学:只学高频用到的,不要一下子都学完,而是先掌握大体框架,后续的用到时再看官方文档,分清学习的先后顺序,先把好拿的分拿到

定义

es是分布式文档系统,一行相当于一个文档(document),只能保存json。

是OLAP(联机分析处理)系统,不是OLTP(联机事务处理)

自带分布式,不依赖zk

es支持的搜索类型:

结构化搜索:可以确定数据结构类型的

非结构化搜索:不能确定数据结构类型

文本搜索

地理位置搜索:查询某点半径范围内的,多边形搜索,是否相交、相离

es支持的查询类型:

es擅长与不擅长:

最擅长从海量数据检索少量相关数据,但不擅长单词查询大量数据(单次导出大量数据)

擅长查询,不擅长写入,写入实时性不高,牺牲写入实时性来实现查询

不支持事务

概念

角色

  • 主节点(active master):活跃的主节点,从候选主节点选出来的,作用:管理集群,应避免主节点做重负载的任务
  • 候选节点(master eligeble):配置文件中配置的master-eligible,主节点发生故障时或第一次启动时,选举和被选举主的节点
  • 数据节点(data node):做数据相关操作,保存、搜索,做大负载的工作,数据节点也可以投票(voting_only的数据节点),但不能被选举
  • 预处理节点(ingest node):数据写入前的预处理操作,过滤

配置:

老的版本用node.master=true、node.data=true,

新版本:node.roles:[master,data],一个节点可以同时是多种角色,默认不配置表示具备所有的角色

索引

GET index_name 查询索引

索引的组成:

  • 别名(alias):
  • settings:索引设置,如分片和副本的数量
  • mapping:映射,定义了索引的字段,字段类型、长度、分词器等

索引可以表示数据文件,也可以表示索引文件,比如倒排索引等

类型

是索引的下一级,7.0可以使用非_doc类型,推荐使用_doc类型,8.0只能用_doc类型

DELETE test_index

PUT /test_index/test_type/1{

...

}PUT /test_index/_doc/1{

...

}

8.0删除了类型的概念

文档

相当于一行,可以通过cat api查询

GET _cat/indices?v 查询所有索引

GET [indexName]/_doc/[id] 查询某个索引的某个文档id

元数据字段(meta data),带下划线的:

_index:索引名称

_id:文档id

_version:文档的版本号,每次修改版本加1

_seq_no

_primary_term

_source

found: 有数据为true

源数据(source data业务数据)字段:_source中的字段

集群

自动发现

默认是零配置自动发现的,会自动绑定本地回环地址,并扫描本地端口9300~9305上运行的其它节点,自动形成集群

network.host: 提供服务的IP地址,默认本地唤回地址,配置此项会导致开发模式转向生产模式,从而触发引导检查

network.publish.host:节点间通信的公网地址

http.port:服务端口号,默认9200~9299

transport.port:节点间通信的端口号,默认9300~9399

discovery.seed_hosts:候选节点列表(master-eligible),ip+port

cluster.initial_master_nodes:首次启动时的候选节点,只有第一次启动需要,之后可以删除,如果配置了network.host,此项必须配置

m:master, d:data, v: voting only经投票节点

作业:5 nodes,3候选,2master role,1进投票和data,2data, 2m, 1mdv,2d

分片:索引分为多个分片,每个分片保留一部分数据,p

副本:分片的备份,一个分片对应多个副本,r

分片号:分片和对应的副本分片号相同

集群健康状态:可以通过head、elasticvue插件查看,或者_cat/health?v,_cluster/health

绿色:所有分片都可用

黄色:至少有一个副本不可用,但所有主分片都可用

红色:有一个主分片不可用,数据不完整

集群故障诊断

_cat/indices 查询集群索引

_cluster/allocation/explain 诊断分片未分配的原因

分片

主分片(primary shard, P):可读写

副本分片(replica shard, R):只读,

作用:1、备份,容灾。2、提高并发读写能力

分片策略:7.0之前:默认5P, 1R;8.0:默认1P1R

每个分片都是一个Lucene实例

  • 一个文档不可能同时存在于多个主分片,但可以同时存在于多个属于同一主分片的副本
  • 主分片和副本不能存在同一节点(a)
  • 同一主分片的多个副本不能存在于同一节点(b)
  • a和b可以得出:分片号相同的分片(即数据相同的分片)不能存在于同一节点
  • 节点加入和离开时会触发分片再均衡(shard rebalance),使分片尽量平均分布在每个节点,但是再均衡不能违反a和b,如果违反了,则会有未分配的分片

开发工具

es-head,es-vue,kibana

API

索引API

查询

GET _search,在hits.hits中有所有的索引数据,_index:索引名称,_id: 文档号,_source:业务数据

  • 默认只会查前10条,GET _search?size=20
  • took:查询毫秒数,time_out:是否超时

GET [索引名称]/_search,查某个索引的

GET [索引名称]/_search?from=9&size=100&timeout=10,分页查询,从第九个开始(默认是0,从第一条开始),查100条,timeout:查询超时时间

PUT [index_name]:创建索引,默认别名和映射为空

GET [index_name]:查询索引的别名(alias)、映射(mapping)、设置(setting),设置包括number_of_shards主分片数,副分片数

http 复制代码
//创建索引,已存在则失败
PUT [index_name]
{
  "settings":{
    "number_of_shards":1,//主分片数
  	"number_of_relicas":1//每个主的副本数
  }
}
//修改索引的设置,已打开的索引的主副分片数不能修改
PUT [index_name]/_settings
{
	"number_of_shards":2
}

静态索引设置:只能在创建索引或索引关闭时设置,比如主分片数,每个索引的分片数上限是1024

动态索引设置:可以通过_setting API实时修改的,比如副分片数、index.refresh_interval(索引刷新频率,默认1s,写入后多久才能查到)、index.max_result_window(_search API查询的窗口数限制,from+size不能超过,默认10000,比如from=9990,size=11,则报错,size=10可以)

索引命名规范:

  • 必须小写、不能特殊符号、不能中文、可以_ - +三种,不能超过255字节
  • 应该小写英文字母下划线命名,不能驼峰

删除索引:DELETE [index_name]

判断索引是否存在:HEAD [index_name],返回404表示索引不存在,GET也可以
索引的不可变性

  • 索引名称创建后不能修改,如果要修改只能重建索引,代价较高,可以通过别名
  • 打开状态的索引的主分片数量不能修改
  • 字段类型不可变

GET [ind]/_count 查询索引文档数

reindex:通过指定源索引和目标索引,重新创建索引文档 ,源索引必须有文档,才会创建目标索引,并且只会复制文档,其它的不会复制,比如映射

http 复制代码
POST _reindex
{
	"source":{
  	"index":[source_index_name]
	},
	"dest":{
  	"index":[dest_idx]
  }
}

文档API

创建文档

op_type:

  • index: 文档id不存在则创建,存在则替换,是全量更新,将所有字段更新,未指定的字段会被删除
  • create:文档id不存在则创建,存在则报错

均为写操作,都发生在P shard

http 复制代码
//create
PUT /[idx_name]/_doc/[id]?op_type=create
{
	"name":"",
	"content":""
}
//简化写法,与上面的等价
PUT /[idx_name]/_create/[id]
{
	"name":"",
	"content":""
}
//index
PUT /[idx_name]/_doc/[id]?op_type=index
{
	"name":"",
	"content":""
}
//不加op_type相当于op_type=index
PUT /[idx_name]/_doc/[id]
{
	"name":"",
	"content":""
}
//自动生成id,不指定id即可,会生成一字符串格式的id
POST /[idx_name]/_doc
{
	"name":"",
	"content":""
}
GET [idx_name]/_search/

查询文档

GET [idx_name]/_doc/[id] 查询文档,found=false表示文档不存在

HEAD [idx_name]/_doc/[id] 检查文档是否存在

GET [idx_name]/_doc/[id]?source=false 只查询元字段(meta data),不查询源字段(source data,业务数据)

GET [idx_name]/_source/[id] 只查源字段

DELETE [idx_name]/_doc/[id] 删除某个文档

部分字段更新文档

  • 部分更新字段:使用POST,uri使用_update,字段放在doc中。如果不放在doc中,或者uri中使用_doc,仍为全量更新
  • 创建时不能加doc,否则会当成业务字段
http 复制代码
//7.x,8.x不支持
POST [idx_name]/_doc/[id]/_update
{
	"doc":{
  	"name":""
  }
}
//只更新指定字段,未指定的字段不变
POST [idx_name]/_update/[id]
{
	"doc":{
  	"name":""
  }
}

批量

http 复制代码
//批量查不同索引的文档
GET /_mget
{
	"docs":[
  	{
  		"_index":"[idx_name]",
    	"_id":"[doc_id]",
    	"_source":false//只查元字段
		},
  	{
  		"_index":"",
    	"_id":""
		}
  ]
}
//批量查某个索引的文档
GET [idx_name]/_mget
{
	"ids":["",""]
}
http 复制代码
//批量写入的action和data必须各自只占一行,一共3行,action包括create和index、update、delete
POST _bulk
POST [idx_name]/_bulk
{"action":{"meta data"}} //必须只占一行
{"data"} //必须只占一行
//批量创建多个索引,并为每个索引添加文档
POST _bulk
{
	"create":{
  	"_index":"[idx_name]",
  	"_id":"[doc_id]"
  }
}
{
	"name":""
	"content":""
}
{
	"create":{
  	"_index":"[idx_name1]",
  	"_id":"[doc_id]"
  }
}
{
	"name":""
	"content":""
}
POST _bulk
{"create":{"_index":"test_bulk1","_id":1}}
{"name":"陈文捷","age":27}
{"create":{"_index":"test_bulk2","_id":1}}
{"name":"陈文捷2","age":28}

POST _bulk
{
	"update":{
  	"_index":"[idx_name]",
  	"_id":"[doc_id]"
  }
}
{
	"doc":{
	"name":""
	"content":""}
}
POST _bulk
{
	"delete":{
  	"_index":"[idx_name]",
  	"_id":"[doc_id]"
  }
}

POST _bulk
{"create":{"_index":"test_bulk1","_id":1}}
{"name":"陈文捷","age":27}
{"create":{"_index":"test_bulk2","_id":1}}
{"name":"陈文捷2","age":28}

POST _bulk
{"update":{"_index":"test_bulk1","_id":1}}
{"doc":{"age":29}}
{"update":{"_index":"test_bulk2","_id":1}}
{"doc":{"age":29}}

POST _bulk
{"delete":{"_index":"test_bulk1","_id":1}}
{"delete":{"_index":"test_bulk2","_id":1}}

GET _mget
{
  "docs": [
    {
      "_index": "test_bulk1",
      "_id":"1"
    },{
      "_index":"test_bulk2",
      "_id":"1"
    }
  ]
}

action:

  • create:创建,索引已存在则报错
  • index:创建,存在则全量替换
  • update: 部分字段更新
  • delete:只需要action行,不需要data行

bulk api对json串有严格的要求,每个操作必须2个json串,2行,性能

delete by query

通过等值条件来删除

http 复制代码
POST [idx]/_delete_by_query
{
	"query":{
  	"term":{
    	"price":6999 //price字段是6999的删除
  	}
	}
}

查询API

  • _source:过滤结果集字段,相当于select f1,f2...,支持通配符"*"。可以直接指定一个数组,表示只查询满足条件的字段,也可以使用include和exclude,同时指定时,会先执行include过滤,再在include基础上执行exlude过滤。为false时,表示不查询源数据,只返回元字段
  • 分页:根据from、size分页,前者指定分页偏移量,后者指定分页大小,默认是0和10,from+size默认不能超过10000,因为es是分布式数据库,分页时需要将排序后from+size条满足条件的数据拉取到一起返回,太大oom。如果需要偏移超过10000的分页,用search_after。

排序

  • 使用sort指定排序字段,值是一个数组,其中的元素可以为字段名称、对象、_score、_doc
  • 为字段名称时,默认升序;_score默认按照分值降序;_doc表示索引中存储的顺序(文档添加的顺序)
  • 为对象时,对象中的key是字段名称,对应的值有order:asc/desc。
  • mode:用于设置数组类型的字段取哪个元素的值来参与排序,min取最小值,max最大值,avg取平均值,sum取总和
  • numeric_type:可以同时查询多个索引,逗号分割,GET idx1,idx2/_search,对其中名称相同,类型不同的数值类型的字段,可以通过numeric_type指定先转成什么类型,再排序,比如long和double可以统一转成long
  • sort支持多个字段排序,前面相同的,使用后面的排序规则

查询

  • 全文检索:无搜索条件边界,召回结果取决于相关性,而相关性计算无明确边界性条件,如同义词、谐音、别名、错别字、混淆词等均可成为相关性判断依据
  • es实现的全文检索:包含2个过程:1、TEXT类型的字段插入时,会经过文档归一化器和分词器处理,得到多个词项,然后根据词项到包含该词项的文档的ID的映射,也就是倒排索引。2、搜索时,搜索字段也会经过分词器得到词项,然后在倒排索引中匹配。
  • match:将搜索词分词成词项后,依次和文档中的词项匹配,如果只有query参数,可以省略它,operator: and/or, query查询词的每个词项匹配文档词项之间是and还是or关系,默认or,只要有一个查询词项匹配文档词项,该文档匹配,改成and时,所有查询词项都匹配文档词项时,文档匹配。
  • math_phrase: 也会将搜索词分词,但和文档词项匹配时,搜索词项顺序必须和文档词项一致,并且对应的文档词项间隔的词项数必须小于等于slop,slop默认0。和match的区别:math_phrase查询结果集更小,相关度更高,match对搜索词的顺序和对应的文档词项间隔没有限制。
  • term: 不会对搜索词进行任何处理,包括大小写、标点、分词等,和match的区别:match会对搜索词进行分词处理,适用于text,而term适用于非text类型字段,比如keyword,date,numeric。它们只决定是否对搜索词进行分词,而文档字段的分词取决于是否text类型
  • 自动映射生成的text类型的字段会包含一个keyword类型的子字段,term查询时通过[field].[子字段名称]查询
  • term查询时,大小写不匹配查询不到,text分词后的词项默认会转成小写
  • term查询不会分词的字段时,相当于等值查询,如果字段有多个值(数组类型),等于其中一个值则文档匹配
  • terms: 相当于in查询

组合查询

  • 支持多条件查询,
  • must和filter: 与
  • should:其中至少minimum_should_match个条件满足时为true,否则false,minimum_should_match默认是1,所以should默认是或
  • must_not:等价于must取反
  • must和should会计算相关度评分,filter和must_not不会, score为0,如果不需要评分,应该将must替换为filter
  • bool可以嵌套,从而嵌套条件,bool相当于括号
  • bool默认逻辑关系是且, filter和must可以同时使用,将不需要计算评分的条件放到filter里,从而减少must需要计算的分值个数,比如按照价格范围和名称查询,价格范围查询不需要计算评分,那么可以将价格范围条件放到filter,名称查询放到must
  • filter:忽略评分、缓存
http 复制代码
GET test_index3/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              {
                "term": {
                  "name": "chenwenjie"
                }
              },
              {
                "term": {
                  "age":  28
                  
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "term": {
                  "name": "guojing"
                }
              },
              {
                "term": {
                  "age":  28
                  
                }
              }
            ]
          }
        }
      ]
    }
  }
}
bash 复制代码
GET test_index4/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "type": "shouji"
          }
        }
      ],
      "filter": [
        {
          "match": {
            "tags": "xingnengqiang"
          }
        }
      ]
    }
  }
}

桶聚合

  • 定义:桶是所有文档的子集,符合桶条件的文档逻辑上放入对应的桶,桶条件通过聚合类型指定,放入桶时会自动计算桶中文档数
  • 聚合通过aggs指定,需要自定义聚合名称,名称下一级key是聚合的类型,聚合类型:terms、range
  • terms类型:桶是指定字段key的值
  • size:聚合结果的个数,默认只返回前10条文档数最多的,没返回的数量是sum_other_doc_count
  • 聚合是近似值
  • text类型不能聚合
  • shard_size(https://blog.csdn.net/UbuntuTouch/article/details/104141398):如果有多个主分片,聚合实际上分为2部,类似于map-reduce,先对每个分片单独聚合(map),再将分片聚合结果汇总聚合(reduce),reduce时,每个分片聚合结果最多取前文档数最多的shard_size个,从而减少分片数据传输的时间。shard_size默认大于size,为size * 1.5 + 10,如果等于size,如果某个聚合key数据倾斜严重,在某些分片文档很多,而在其他分片文档很少,那么reduce时,会导致文档数多的分片取了该key,而文档数少的分片没取,造成结果数量不对。适当调大shard_size可以使聚合结果更精确,但查询更慢
  • show_term_doc_count_error:如果为true,聚合结果中的每个聚合key会显示doc_count_error_upper_bound,它是对应聚合key在每个分片中未被统计进shard_size的数量,如果大于0,说明对应的聚合key统计不准确,可以通过调大shard_size,直到为0
  • range:通过from、to定义桶的范围,指定字段的值符合桶的范围的计入该桶
  • 全局聚合过滤:可以在query的基础上进行聚合,外层的size分页大小不影响聚合,只影响hits.hits结果集的个数,hits.total.value是满足query条件的文档总数,但不超过10000,aggs中的size才是对聚合结果的取前n个
  • aggs中的order:是对聚合结果进行排序,默认按照文档个数倒序,_count=desc,_term按照聚合key排序,还可以通过指定嵌套聚合名称,对其中的嵌套聚合结果进行排序,[嵌套聚合名称].value的value可以省略,其他不能省略,比如stats
http 复制代码
GET test_index4/_search
{
  "_source": false, 
  "aggs": {
    "agg_type": {
      "terms": {
        "field": "type.keyword",
        "shard_size": 20
      }
    }
  }
}
http 复制代码
GET test_index4/_search
{
  "_source": false, 
  "aggs": {
    "agg_type": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "to": 4000
          },
          {
            "from": 4000, 
            "to": 6000
          },
          {
            "from": 6000, 
            "to": 8000
          },
          {
            "from": 8000
          }
        ]
      }
    }
  }
}
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "mmy": {
      "terms": {
        "field": "type.keyword",
        "order": {
          "_count": "asc",
          "my1":"asc"
        }
      },
      "aggs": {
        "my1": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

指标聚合

  • 根据文档的字段计算指标,比如最大值、最小值、平均值等
http 复制代码
GET test_index4/_search
{
  "_source": false, 
  "aggs": {
    "my_agg": {
      "max": {
        "field": "price"
      }
    },
    "my_agg1":{
      "min": {
        "field": "price"
      }
    },
    "my_agg2":{
      "avg": {
        "field": "price"
      }
    },
    "my_agg3":{
      "stats": {
        "field": "price"
      }
    },
    "my_agg4":{
      "value_count": {
        "field": "price"
      }
    },
    "my_agg5":{
      "sum": {
        "field": "price"
      }
    }
  }
}

管道聚合

  • 将其他聚合结果作为输入,得到新的聚合结果,分为2种:1、Parent: 在父聚合的结果上进一步聚合。2、Sibling:在兄弟聚合的结果上聚合
  • bucket_path:用于指定兄弟聚合的名称,可以通过">"指定兄弟聚合的子聚合,只能是相对路径,并且不能跳到上一级
  • 场景:根据品牌对商品桶聚合,对每个桶计算价格平均数(父聚合),计算价格平均数最小的品牌(兄弟聚合)
  • min_bucket是兄弟聚合
http 复制代码
GET test_index4/_search
{
  "_source": false, 
  "aggs": {
    "my_agg": {
      "terms": {
        "field": "type.keyword",
        "size": 10
      },
      "aggs": {
        "my_agg1": {
          "avg": {
            "field": "price"
          }
        }
      }
    },
    "my_agg2":{
      "min_bucket": {
        "buckets_path": "my_agg>my_agg1"
      }
    }
  }
}

doc_values, index

  • doc_values: 排序和聚合需要根据文档查找值,也就是正向索引,doc_values用于开启正向索引,非text和annotated_text类型的字段默认开启,因此只有text和annotated_text类型的字段不支持排序和聚合,如果某个字段不需要排序和聚合,可以将doc_values设为false,从而节约磁盘空间。对为false的字段排序或聚合会报错: Can't load fielddata on [name.keyword] because fielddata is unsupported on fields of type [keyword]. Use doc values instead.
  • index:是否创建反向索引,默认true,为fasle的字段不能搜索,会报Cannot search on field [type] since it is not indexed.
  • 反向索引是值到文档的映射,记录了值出现在哪些文档中;正向索引记录的文档中有哪些值,对过滤结果进行聚合时,过滤结果通常是一部分文档,需要根据这部分文档查找其中的值,反向索引需要扫描整个索引,不适合。
  • text不能开启doc_values,报Failed to parse mapping [_doc]: [text] fields do not support doc values
  • doc_value内部列式存储,便于压缩节约磁盘空间,比如数值类型字段,如果所有的值都相同或都为空,只需要设置标志位、记录一个值;如果都小于256,每个值只需要1字节;如果大于256并且有公约数,除以公约数再存储;如果没有公约数,以最小值为起始值,其他值只存储偏移量。字符串类型可以使用字符串常量池,相同字符串只存储一次,key是整数,又可以使用整数存储。
  • doc_value存储在磁盘上,不会立即fsync刷盘,而是使用os page cache,所以es 堆内存不宜过大,使用了doc_value时,应当小于50%
  • fielddata: 和doc_values一样,也是用于开启正向索引,但存储在堆内存中,并且只有text类型支持fielddata。

聚合filter

  • 使用场景:需要多种条件的聚合结果,比如要返回所有商品的平均售价和电脑的平均售价。和全局聚合过滤的区别:query对所有聚合都生效,而filter只对单个聚合的生效,先执行filter再执行对应的聚合
  • filters聚合:filter条件和聚合key相同时的桶聚合的简写形式,固定2层filters嵌套。
  • 匿名filters:filters聚合内部的聚合名称可以省略,filters可以为数组类型
  • other_bucket:显示不满足filters聚合条件的文档数,结果集默认key为_other_,可以通过other_bucket_key指定,匿名filters时为最后一个bucket
  • 如果同时使用了query和聚合filter,会同时生效,关系为且
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "mmy": {
      "avg": {
        "field": "price"
      }
    },
    "my1": {
      "filter": {
        "term": {
          "type.keyword": "computer"
        }
      }, 
      "aggs": {
        "NAME1": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "my":{
      "filters": {
        "filters": {
          "NAME1": {
            "term": {
              "price": "4999"
            }
          },
          "name2":{
            "term": {
              "type.keyword": "shouji"
            }
          }
        }
      }
    }
  }
}
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "my": {
      "filter": {
        "term": {
          "price": "4999"
        }
      },
      "aggs": {
        "my1": {
          "terms": {
            "field": "price"
          }
        }
      }
    },
    "my2": {
      "filter": {
        "term": {
          "type.keyword": "shouji"
        }
      },
      "aggs": {
        "my3": {
          "terms": {
            "field": "type.keyword"
          }
        }
      }
    }
  }
}
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "my": {
      "filters": {
        "filters": [
          {
            "term": {
              "price": "4999"
            }
          },
          {
            "term": {
              "type.keyword": "shouji"
            }
          }
        ]
      }
    }
  }
}
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "my": {
      "filters": {
        "other_bucket": true, 
        "filters": [
          {
            "term": {
              "price": "4999"
            }
          },
          {
            "term": {
              "type.keyword": "shouji"
            }
          }
        ]
      }
    }
  }
}

global筛选器

  • query筛选条件会对所有聚合生效,而指定了global筛选器的聚合不受query筛选条件的影响
  • 如果指定了global筛选器,必须嵌套一层聚合。global筛选器只能用于顶层聚合,不能用于嵌套聚合,是一种只能用于顶层的聚合类型。
http 复制代码
GET test_index4/_search
{
  "size": 0,
  "query": {
    "term": {
      "type.keyword": {
        "value": "computer"
      }
    }
  },
  "aggs": {
    "computer_bucket": {
      "terms": {
        "field": "type.keyword"
      }
    },
    "all_bucket": {
      "global": {},
      "aggs": { //指定了global筛选器,必须嵌套一层聚合
        "all_bucket1": {
          "terms": {
            "field": "type.keyword"
          }
        }
      }
    }
  }
}

post_filter

  • 先执行query,在执行聚合,最后执行post_filter,它只过滤hits中的结果,不影响聚合结果
  • 使用场景:页面上对查询结果进一步过滤,但聚合统计的结果不变
  • 应该和聚合同时使用,不应该替换filter,因为post_filter会在query之后单独执行,效率更低
  • post_filter和聚合都是在query的基础上过滤或聚合的,它们之间没有关系
http 复制代码
GET test_index4/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "price": {
            "gte": 5000
          }
        }
      }
    }
  },
  "post_filter": {
    "term": {
      "name.keyword": "honor"
    }
  },
  "aggs": {
    "my":{
      "terms": {
        "field": "type.keyword",
        "size": 10
      }
    }
  }
}

top_hits

  • 用于显示桶聚合内的文档详细字段信息,支持分页、_source查询指定字段、排序
  • top_hits必须用在对应聚合的子聚合中,是一种聚合类型,是一种内层的嵌套聚合。
http 复制代码
GET test_index4/_search
{
  "size": 0, 
  "aggs": {
    "my":{
      "terms": {
        "field": "type.keyword"
      },
      "aggs": {
        "NAME": {
          "top_hits": {
            "from": 1, 
            "size": 2,
            "_source": {
              "includes": ["name"]
            },
            "sort": [
              {
                "name.keyword": {
                  "order": "desc"
                }
              }
              ]
          }
        }
      }
    }
  }
}

bucket_sort

  • 对聚合结果进行排序、分页,和terms中定义order类似
http 复制代码
GET test_index4/_search
{
  "size": 0, 
  "aggs": {
    "my":{
      "terms": {
        "field": "type.keyword"
      },
      "aggs": {
        "NAME": {
          "bucket_sort": {
            "from": 0, 
            "size": 10, 
            "sort": [{
              "_count":"asc"
            }]
          }
        }
      }
    }
  }
}

映射

用来定义索引的字段名称、类型、长度,以及如何存储和索引的

GET [idx]/_mapping 查询索引的映射,properties中包含字段定义

GET [idx]/_mapping/field/[field_name] 查询索引的某个字段的定义

子字段:fields

自动映射

写入文档时根据Json字段类型生成Mapping的字段类型

推断规则:

  • null:不添加字段
  • true/fasle: boolean
  • 小数:float
  • 整数:long
  • object:Object
  • 数组:取决于第一个元素的类型
  • 字符串:日期格式:date,其它字符串:text+keyword

自动映射会尽可能使用宽字段类型,容易浪费存储空间,首次环境建议使用手工映射

类型无法修改,只能重建索引

ES字段可以包含子字段,比如text和keyword,

http 复制代码
PUT test_dynamic_mapping
{
  "mappings": {
    "numeric_detection": true,
    "dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss"]
  }
}
POST test_dynamic_mapping/_doc
{
  "field1":false,
  "field2":3.14,
  "field3":52,
  "field4":"abc",
  "field5":"0.618",
  "field6":"2023-05-07 15:00:10"
}
GET test_dynamic_mapping/_mapping

手动映射(explicit mapping)

创建索引时,指定mappings,来显示创建映射

mappings.properties是字段的定义

小技巧:可以使用自动映射创建后,复制mappings定义,删除索引,再重新创建,在自动映射的基础上修改

修改mappings: mappings中有些参数可以修改,比如fielddata;有些重要的参数不能修改,比如类型、分词器

http 复制代码
PUT /[idx]
{
	"mappings":{
  	"properties":{
    	"[field_name]":{
      	"[param_name]":"[param_val]"
    	}
		}
	}
}
PUT /[idx]
{
	"mappings":{
  	"properties":{
    	"text_field":{
      	"type":"text",
      	"fields":{
        	"text_field_keyword":{
          	"type":"keyword"
          }
        }
    	},
    	"long_field":"long"
		}
	}
}
GET test_mapping/_mapping
//在已创建的索引上修改mapping
PUT test_dynamic_mapping/_mapping
{
  "numeric_detection": false,
  "dynamic_date_formats": [
    "yyyy-MM-dd HH:mm:ss"
  ]
}
PUT test_index3/_mapping
{
  "properties": {
    "name": {
      "type": "text"
    }
  }
}

字段数据类型(field data type)

字段类型分为2种:会被分词的(text)、不会的()

  • 数字类型:

  • boolean

  • keywords:包括keyword、constant keyword、wildcard,查询时只能完全匹配

  • dates

  • flattened:

  • Range:范围类型,包括上限和下限,gte、lte指定

  • text:文本数据类型,用于全文检索

  • completion:搜索补全,文本补全

  • geo_point:经纬度

  • geo_shape:多边形

array

  • 其实没有专门的数组类型,任何类型的字段都可以包含0个或多个值,这些值的类型必须相同,动态映射时,数组元素类型取决于第一个添加的文档的第一个元素的类型,后面的元素和文档如果能强转成第一个元素的类型,则可以添加成功,否则文档添加失败
  • 比如"tags": [ "abc",1 ]可以添加成功,因为1可以强转成"1","tags": [ 1,"abc" ]添加失败,"abc"不能转成数字。用_mapping api查看,仍然是数组元素的类型,而不是数组类型。
  • 添加第一个文档时会进行类型推断,后面添加的文档的字段如果不能转换成第一次推断出来的类型,则报错

Text

  • 默认会被分词为词项(term),并创建索引,用于全文检索
  • 自动映射器会自动创建一个keyword类型的子字段
  • analyzer:分词器,创建索引和查询时会执行分词器,search_analyzer: 专门指定查询时使用的分词器,默认和analyzer相同

Keyword

  • 用于精确查询、聚合字段、和query.term查询。
  • 可以指定ignore_above,query.term查询时,在查询结果中,不会查询出超过指定长度时的数据
  • 查询时大小写敏感
  • 和numeric类型的区别:keyword的term查询更快,numeric适合范围查询,不是所有数字类型都适合numeric类型,如果不需要范围查询,建议使用keyword
  • keyword是一个类型族,包含多个类型:keyword, constant_keyword
  • constant_keyword:

Date

  • 默认格式是UTC时间格式,yyyy-MM-ddTHH:mm:ssZ,
  • 可以通过字段属性format来指定格式,epoch_millis时间戳毫秒格式,epoch_second时间戳秒格式,可以指定多个,||分割
  • 时区:yyyy-MM-ddTHH:mm:ss.sss+08:00 东八区,yyyy-MM-ddTHH:mm:ssZ 零时区
  • 内部会统一转成时间戳存储

object

  • 用于存储json对象,对应java中的一个对象
  • 内部实际上还是key-value的形式保存,key是多层级字段,value是最后一层字段的值,比如"manager.name.first": "John"
  • 手动映射时,可以通过properties指定对象内部字段的类型

映射参数(mapping parameter)

映射参数是mappings.properties.[field]中指定的参数

  • analyzer:指定分词器,用于text类型的字段
  • coerce:是否允许强制类型转换,比如字段类型定义的是interger,写入的是"1",coerce=false时,报错,为true是,写入成功,默认为true。可以在索引级别和字段级别设置,索引级别:settings.index.mapping.coerce
  • copy_to:用于指定字段写入时复制到另一个字段,用于多字段搜索
http 复制代码
"first_name":{
	"type":"text",
	"copy_to":"full_name"
},
"last_name":{
	"type":"text",
	"copy_to":"full_name"
},"full_name":{
	"type":"text"
}
  • enabled:当mappings.enabled=false时,当前索引的所有字段会存储,但不会创建倒排索引,query.match.[field]搜不到。如果对某个字段进行指定,则这个字段类型必须是object。为false的字段只会存储,不会解析和索引,因此根据该字段搜索不到文档。当把所有字段都enable设为false时,只能根据文档ID搜索文档。
  • fields:用于为一个字段指定多个子字段,不同的子字段可以使用不同分词器。Text一般都有一个keyword类型的子字段,因为Text类型会分词和倒排索引,不支持排序,可以通过指定keyword子字段来支持排序。子字段不会继承父字段任何属性,可以独立指定映射参数。
http 复制代码
"test_f":{
	"type":"text",
	"fields":{
  	"chinese":{
    	"type":"keyword",
    	"ignore_above":5//字段长度超过5时,query查不到
    },
  	"english":{
    	"type":"text",
    	"analyzer":"english"
    }
}
Post test_fields/_doc
{
	"test_f":"english abcd"
}
GET test_fields/_search
{
	"query":{
  	"match":{
    	"test_f.chinese":"english abcd"//搜索字段包含指定值的
    }
  }
}
  • format:用于格式化,比如日期
  • ignore_above:用于keyword类型,插入文档时,超过指定长度的字段值被忽略,忽略的意思是会被存储,查所有时能查出来,但不会建立索引,不能根据该字段搜到文档。可以理解为超长的时候,enable=false。
  • index:用于关闭某个字段的倒排索引,true、false,关闭后query.match查不到,会报错,没有创建索引
  • meta:用于字段的元字段,对es是透明的,es不对其做任何处理,用于业务上区分
  • norms: 是否禁用评分,禁用可以优化性能
  • null_value:为null值设置默认值
  • properties:用于声明字段
  • similarity:用于为字段设置评分算法,8.0后删除了classic算法,5.0~7.17默认是BM25,可选配置是boolean和classic(TF-IDF)
  • store:用于为字段指定单独的存储区域,查询时可以通过store_fields指定查询store的字段, _source=true查询_source字段。字段分为2块存储区域,source和store

自动映射模板(Dynamic Templates)

由条件和映射组成,写入数据时,如果条件匹配则使用配置的mapping,否则使用自动映射器,为一类相同或相似特征的字段定义相同的映射

可以定义多个模板,每个模板包含一或多个条件和一个mapping

匹配条件:

  • match_mapping_type
  • match、unmatch
  • path_match

定义

http 复制代码
"dynamic_templates":[
	{
  	"[template_name]":{
    	[match conditions]
    	"mapping":{...}
    }
  },{}...
]

匹配条件

match_mapping_type

用于匹配数据类型

http 复制代码
//将数值类型的值的字段创建为integer类型,文本类型的值字段创建为keyword类型
//数值类型默认是long,将他映射为integer
PUT idx
{
	"mappings":{
  	"dynamic_templates":[
    	{
  			"integers":{//模板名字
        	"match_mapping_type":"long",
        	"mapping":{
          	"type":"integer"
          }
        }
			},
    	{
      	"strings":{
        	"match_mapping_type":"string",
        	"mapping":{
          	"type":"keyword"
          }
        }
      }
    ]
  }
}
match、unmatch

根据字段名称匹配

http 复制代码
//字段类型是string,字段名称以num_开头,不以_text结尾的字段,映射为long
PUT idx
{
	...
	"[temp_name]":{
  	"match_mapping_type":"string",
  	"match":"num_*",
  	"unmatch":"*_text",
  	"mapping":{
    	"type":"long"
    }
  }
}

PUT ...
{
	"num_interger":5,//类型不匹配
	"num_long":"5",//匹配
	"num_text":"foo"//名称不匹配
}
path_match、path_unmatch

用于对象类型字段的匹配,和match类似,但是它使用完整限定名的字段名来匹配

http 复制代码
PUT ..
{
	...
	"full_name":{
  	"path_match":"name.*",
  	"path_unmatch":"*.middle",
  	"mapping":{
    	"type":"text",
  		"copy_to","full_name"//将字段拷贝到full_name,只对查询query可见,full_name本身使用自动映射器
    }
  }
}
PUT ...
{
	"name":{
  	"first":"elastic",//匹配
  	"middle":"org",//不匹配
  	"last":"cn"//匹配
  }
}
GET .../_search
{
	"query":{
  	"match":{
    	"full_name":"elastic"//能搜索到,搜索org不能搜索到
    }
  }
}
模板变量

是一个占位符变量({name}、{dynamic_type}),可以根据字段的信息动态使用相应的值

  • {name}:字段名称
  • {dynamic_type}:字段匹配的类型
http 复制代码
"named_analyzers":{
	"match_mapping_type":"string",
	"match":"*",
	"mapping":{
  	"type":"text",
  	"analyzer":"{name}"//使用和字段名称一样的分词器,分词器未定义则报错
  }
}
PUT ...
{
	"english":"xxx x"//字段的分词器是english
}
"test":{
	"match_mapping_type":"*", 
	"mapping":{
  	"type":"{dynamic_type}",//所有非文本类型的字段
  	"doc_values":false 
  }
}

分词器(Text Analysis)

检索:和简单的搜索不同,更注重相关性,为了满足用户需求

分词发生时期:

  • Index Time(创建倒排索引的时期):源数据分词
  • search time(搜索时期):对搜索词进行分词

倒排索引存储了词项和包含词项的文档ID的对应关系:

  • Term Dic: 搜索内容分词后的词项
  • Posting List:包含词项的文档ID

分词器的组成

字符过滤器(char_filter):用于处理单个字符

词项过滤器(filter)

切词器(tokenizer): 定义了分词器的切词规则

注意:源数据和倒排索引是分开存储的,分词器处理的是倒排索引,也就是词项,不会对源数据造成任何影响

http 复制代码
"settings":{
	"analysis":{
  	"char_filter":{},
  	"filter":{},
  	"tokenizer":{}
  }
}

analyzer API

http 复制代码
//查看分词结果,默认使用默认分词器,可以通过anayzer指定分词器
GET _analyze
{
	"text":["What are you doing"],//测试文本
	"analyzer":"standard"//默认分词器是standard,也可以指定为english
}

切词器(tokenizer)

http 复制代码
GET _analyze
{
	"text":["What are you doing"], 
	"tokenizer":"standard" //默认的切词器
}

词项过滤器(token filter)

用来处理切词器切词后的词项,如大小写转换,删除停用词和同义词处理

http 复制代码
GET _analyze
{
	"text":["What are you doing"], 
	"filter":["lowercase"]//使用词项过滤器,这里不会切词,将text整体作为一个词项
}
GET _analyze
{
	"text":["What are you doing"], 
	"tokenizer":"standard", 
	"filter":["lowercase"]
}
GET _analyze
{
	"text":["What are you doing"], 
	"tokenizer":"standard", 
	"filter":["stop"]//停用词,默认使用预制的停用词
}
//自定义停用词
PUT [idx]
{
	"settings":{
  	"analysis":{
    	"filter":{
      	"my_filter":{//词项过滤器名
        	"type":"stop",
        	"stopwords":["www"],//内联的方式配置停用词,不能修改
          "stopwords_path": "stop_words_test.txt"//外部文件配置停用词,可以是相对于config的路径,utf8编码,每个停用词占一行,这种方式可以动态修改停用词
        	"ignore_case":true
        }
      }
    }
  }
}
GET [idx]/_analyze//使用某个索引的自定义分词器
{
	"tokenzier":"standard",
	"fitler":["my_filter"],
	"text":["What www WWW are you doing"]
}

同义词

  • a,b,c=>d,e,f:分词时,a、b、c替换成d、e、f, 搜abc,会搜到d、e、f
  • a,b,c,d:abcd等价,搜其中任何一个,其他的词项都能搜到,相当于a,b,c,d=>a,b,c,d的简写

定义方式:

  • 内联:在synonyms中定义,修改需要重新创建索引
  • 通过synonyms_path定义,同义词定义在文件中,可以动态修改
http 复制代码
PUT [idx]
{
	"settings":{
  	"analysis":{
    	"filter":{
      	"my_synonym":{ 
        	"type":"synonym",
        	"synonyms":["a,b,c=>d",]//内联的方式
        }
      }
    }
  }
}
GET [idx]/_analyze//使用某个索引的自定义分词器
{
	"tokenzier":"standard",
	"fitler":["my_synonym"],
	"text":["a"]
}
PUT [idx]
{
	"settings":{
  	"analysis":{
    	"filter":{
      	"my_synonym":{ 
        	"type":"synonym",
        	"synonyms_path":"anaylisis/syn.txt",//相对路径config目录,每行一个同义词规则
        	"expand":true//默认是true,只对逗号分割的停用词有效,为true时,a,b,c相当于a,b,c=>a,b,c,为false时a,b,c相当于b,c=>a
        	"lenient":false//同义词规则是否宽松,默认false,表示同义词中包含停用词时,索引创建失败;为true时,同义词中可以包含停用词,只是会自动去掉停用词
        }
      }
    }
  }
}

字符过滤器

分词之前的预处理,过滤无用字符,可以添加、修改、删除字符串

字符过滤器-》切词器-》词项过滤器

类型:

  • html_strip:过滤html标签
  • mapping:替换指定字符,如果替换后的字符是停用词,则切词后不会有替换后的字符;如果不是停用词,则切词后会有替换后的字符。替换的key和value都可以是字符串,如果有多个匹配的key,选择最长的。可以替换成空字符。定义方式:1、内联(mappings参数)。2、外部文件(mappings_path),相对于config目录,每个key value一行,utf8
  • pattern_replace:正则替换,将符合正则的字符替换成指定字符
http 复制代码
PUT [idx]
{
	"settings":{
  	"analysis":{
    	"char_filter":{
      	"my_char_filter":{ 
        	"type":"html_strip",
        	"escaped_tags":["a"]//要保留的HTML标签
        }
      }
    }
  }
}
//analyzer API验证分词结果
GET idx/_analyze
{
	//"tokenizer":"standard",//如果不用切词器,则将text作为一个完整的词项;
	"char_filter":["my_char_filter"],
	"text":["<p>I&nbsp;m so <a>happy</a>!</p>"]
}

PUT [idx]
{
	"settings":{
  	"analysis":{
    	"char_filter":{
      	"my_char_filter1":{ 
        	"type":"mapping",
        	"mappings":[
          	"滚=>*","垃=>*","圾=>*",
						"壹=>1","abc=>efgh","艹=>"
          ]
        }
      }
    }
  }
}
//analyzer API验证分词结果
GET idx/_analyze
{
	//"tokenizer":"standard",
	"char_filter":["my_char_filter1"],
	"text":["你就是个垃圾!滚"]
}

PUT [idx]
{
	"settings":{
  	"analysis":{
    	"char_filter":{
      	"my_char_filter1":{ 
        	"type":"pattern_replace",
        	"pattern":"""(\d{3}\d{4}(\d{4}))""",
        	"replacement":"$1****$2"
        }
      }
    }
  }
}
GET idx/_analyze
{
	//"tokenizer":"standard",
	"char_filter":["my_char_filter1"],
	"text":"您的手机号是13516707749"
}

内置分词器

  • standard:默认分词器,中文回逐字拆分
  • whitespace:根据空白分割符分割,会保留大小写和时态,standard会转小写,而whitespace只会分割不转小写
  • keyword:不做任何处理
  • 语言分词器:english、...
http 复制代码
GET _analyze
{
	"analyzer": "standard" ,
	"text":"您的手机号是"
}

自定义分词器

组件定义规则

  • 切词器:一个分词器只能使用一个,但可以在analysis.tokenizer定义多个
  • 词项过滤器:一个分词器可以使用0个或多个
  • 字符过滤器:一个分词器可以使用0个或多个

分词器必须在索引中创建,analyzer api使用也必须加上索引名称

在索引中应用分词器:在settings中定义分词器,在mappings中将字段和分词器绑定,query.match全文检索时,自定义分词器生效,而文档查询查的是源数据,不变

analyzer和search_analyzer

  • 前者是源数据的分词器,后者是搜索词的分词器
  • 后者未指定时,默认等于前者
  • 都未指定时,都为standard分词器
http 复制代码
PUT idx
{
	"settings":{
  	"analysis":{
      "tokenizer":{
      	"my_tokenizer":{
        	"type":"pattern",
        	"pattern":[",.!?"]
        }
      },
      "char_filter":{
      	"my_char_filter":{ 
        	"type":"html_strip",
        	"escaped_tags":["a"]//要保留的HTML表情
        } ,
      	"my_mapping_char_filter":{
        	"type":"mapping",
        	"mappings":[
          	"滚=>*","垃=>*","圾=>*"//*是默认的停用词,分词结果中不会显示,也可以替换成其他的字符
          ]
        }
      },
      "fitler":{ 
      	"my_fitler":{
        	"type":"stop",
        	"stopwords":["www"],
        	"ingore_case":true
        }
      },
    	"analyzer":{
      	"my_analyzer":{
        	"type":"custom",//可以省略
        	"tokenizer":"my_tokenizer"//只能定义一个
        	"char_filter":["my_char_filter","my_mapping_char_filter"]//可以0个或多个
        	"filter":["my_fitler","uppercase"]//可以0个或多个 
        }
      }
    }
  },
	mappings:{
  	properties:{
    	"title":{
      	"type":"text",
      	"analyzer":"my_analyzer"//title字段使用自定义分词器
      }
    }
  }
}
GET idx/_search{
	"query":{
  	match:{//match全文检索,会使用分词器,搜索词也会使用相同的分词器
    	"title":"www"
    }
  }
}
GET idx/_search/_doc
GET idx/_analyze 
{
	"analyzer": "my_analyzer" ,
	"text":"asd垃圾sas滚df,<a>www</a>.baidu!com?<p>cn</p> easffes"
}
http 复制代码
PUT idx{
		mappings:{
  	properties:{
    	"title":{
      	"type":"text",
      	"analyzer":"my_analyzer",
      	"search_analyzer":"my_search_analyzer"
      }
    }
  }
}

文档归一化器(normalizer)

大小写统一,时态转换,停用词(语气词、介词在大多数场景下无搜索意义)

作用:增加召回率,减少匹配次数

  • 和分词器类似,也有字符过滤器和词项过滤器,但没有切词器
  • 只能用于keyword类型的字段
  • 不能被分词
  • 搜索词也会使用字段的normalizer,不会分词
http 复制代码
PUT idx{
	"settngs":{
  	"analysis":{ 
    	"normalizer":{
      	"my_normalizer":{
        	"filter":["uppercase"]
        }
      }
    }
  }
	"mappings":{
  	"properties":{
    	"title":{
      	"type":"keyword",
      	"normalizer":"my_normalizer"
      },
    	"content":{
      	"type":"text",
      	"analyzer":"my_analyzer"
      }
    }
  }
}

中文分词器

下载ik分词器zip,复制到plugins目录解压,需要删除zip,重启es

http 复制代码
GET _analyze
{
	"analyzer":"ik_max_word",
	"text":["我学习 Elasticsearch 选择 Elastic开源社区"]
}
GET _analyze
{
	"analyzer":"ik_smart",
	"text":["中华人民共和国国歌"]
}
GET _analyze
{
	"analyzer":"ik_max_word",
	"text":["特斯拉比亚迪蒙迪欧霸道蒙迪欧大G"]//词库中没有的词分不出来
}
PUT idx{ 
	"mappings":{
  	"properties":{
    	"title":{
      	"type":"text",
      	"analyzer":"ik_max_word"
      }
    }
  }
}
PUT test/_doc
{
	"title":"我爱中华人民。。。"
}
Get test/_search
{
	"query":{
  	"match":{
    	"title":"中华"
    }
  }
}
GET _analyze
{
	"analyzer":"ik",
	"text":["奥利给yydsasd绝绝子"]
}

默认词库在config目录

IKAnalyzer.cfg.xml:配置字典文件和停用词文件

*.dic:预定义的中文词库,比如main.dic主词库,stopword.dic停用词库,quantifyer.dic计量单位,suffix.dic地理位置后缀,surname.dic姓氏

2种分词器:

  • ik_max_word:最细粒度拆分,词项较多,每个有意义的词都会拆分
  • ik_smart:最粗粒度

自定义本地词库:每行一个词项,修改IKAnalyzer.cfg.xml,ext.dic中配置自定义词库,相对路径config目录,可以分号分割多个,需要重启

远程词库热更新:IKAnalyzer.cfg.xml的remote_ext_dic,其中的值是url,需要自己定义http接口,body返回词库内容,header需要包含last-modified或Eflag,都是字符串类型,es会根据这2个值是否发生改变来判断是否更新词库,

本地停用词和远程停用词:ext_stopwords和remote_ext_stopwords

ik可能有bug,远程热更新的词库第一行需要换行符,第一个词项才能生效

本地词库和远程词库:优点是上手简单,缺点是直接操作磁盘文件,词项多时不便管理

mysql热更新

需要修改ik源码

Dictorynary.initial,loadMysqlExtDict, 读取jdbc-relead.properties,根据配置的url、username、password、刷新间隔、查询远程词库和停用词的SQL

误区

分词器(包括3个组件)只会影响倒排索引的结果,不影响源数据

同义词a,b,c,d=>s,建倒排索引时,都会替换成s,搜索时,用abcds任何一个搜索,搜索词也会替换成s,因此查询结果中abcds都包含,搜索结果是源数据

搜索

检索:根据相关性

请求上下文:查询的json对象

响应上下文:返回的JSON

相关度评分

用来对搜索结果进行排序,评分高的排序靠前

5.x之前默认TF/IDF,5.x之后默认BM2.5

查询DSL

http 复制代码
PUT goods
{
	mappings:
  	_source:
    	excludes:[]//定义mappings时,定义查询结果只要哪些字段
    	includes:[]
}
GET goods/_search
{
	"_source":{
  	"includes":["name","tags"]//查询结果只包含哪些字段
  	"excludes":[]//查询结果排除哪些字段
  }
}
GET goods/_search
{
	"_source":{
  	"includes":"*"//支持通配符,t*
  	"excludes":[]//查询结果排除哪些字段
  }
}
相关推荐
num_killer2 小时前
小白的Langchain学习
java·python·学习·langchain
期待のcode3 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐3 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲3 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红3 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥3 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
小楼v3 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地3 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209254 小时前
Guava Cache 原理与实战
java·后端·spring
yangminlei4 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot