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主分片数,副分片数

//创建索引,已存在则失败
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:通过指定源索引和目标索引,重新创建索引文档,源索引必须有文档,才会创建目标索引,并且只会复制文档,其它的不会复制,比如映射


POST _reindex
{
	"source":{
  	"index":[source_index_name]
	},
	"dest":{
  	"index":[dest_idx]
  }
}

文档API

创建文档

op_type:

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

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

//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,否则会当成业务字段
//7.x,8.x不支持
POST [idx_name]/_doc/[id]/_update
{
	"doc":{
  	"name":""
  }
}
//只更新指定字段,未指定的字段不变
POST [idx_name]/_update/[id]
{
	"doc":{
  	"name":""
  }
}

批量

//批量查不同索引的文档
GET /_mget
{
	"docs":[
  	{
  		"_index":"[idx_name]",
    	"_id":"[doc_id]",
    	"_source":false//只查元字段
		},
  	{
  		"_index":"",
    	"_id":""
		}
  ]
}
//批量查某个索引的文档
GET [idx_name]/_mget
{
	"ids":["",""]
}
//批量写入的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

通过等值条件来删除

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:忽略评分、缓存
GET test_index3/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              {
                "term": {
                  "name": "chenwenjie"
                }
              },
              {
                "term": {
                  "age":  28
                  
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "term": {
                  "name": "guojing"
                }
              },
              {
                "term": {
                  "age":  28
                  
                }
              }
            ]
          }
        }
      ]
    }
  }
}
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
GET test_index4/_search
{
  "_source": false, 
  "aggs": {
    "agg_type": {
      "terms": {
        "field": "type.keyword",
        "shard_size": 20
      }
    }
  }
}
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
          }
        ]
      }
    }
  }
}
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "mmy": {
      "terms": {
        "field": "type.keyword",
        "order": {
          "_count": "asc",
          "my1":"asc"
        }
      },
      "aggs": {
        "my1": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

指标聚合

  • 根据文档的字段计算指标,比如最大值、最小值、平均值等
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是兄弟聚合
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,会同时生效,关系为且
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "mmy": {
      "avg": {
        "field": "price"
      }
    },
    "my1": {
      "filter": {
        "term": {
          "type.keyword": "computer"
        }
      }, 
      "aggs": {
        "NAME1": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
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"
          }
        }
      }
    }
  }
}
GET test_index4/_search
{
  "size": 0,
  "aggs": {
    "my": {
      "filters": {
        "filters": [
          {
            "term": {
              "price": "4999"
            }
          },
          {
            "term": {
              "type.keyword": "shouji"
            }
          }
        ]
      }
    }
  }
}
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筛选器只能用于顶层聚合,不能用于嵌套聚合,是一种只能用于顶层的聚合类型。
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的基础上过滤或聚合的,它们之间没有关系
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必须用在对应聚合的子聚合中,是一种聚合类型,是一种内层的嵌套聚合。
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类似
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,

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;有些重要的参数不能修改,比如类型、分词器

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:用于指定字段写入时复制到另一个字段,用于多字段搜索
"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子字段来支持排序。子字段不会继承父字段任何属性,可以独立指定映射参数。
"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

定义

"dynamic_templates":[
	{
  	"[template_name]":{
    	[match conditions]
    	"mapping":{...}
    }
  },{}...
]

匹配条件

match_mapping_type

用于匹配数据类型

//将数值类型的值的字段创建为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

根据字段名称匹配

//字段类型是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类似,但是它使用完整限定名的字段名来匹配

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}:字段匹配的类型
"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): 定义了分词器的切词规则
注意:源数据和倒排索引是分开存储的,分词器处理的是倒排索引,也就是词项,不会对源数据造成任何影响

"settings":{
	"analysis":{
  	"char_filter":{},
  	"filter":{},
  	"tokenizer":{}
  }
}

analyzer API

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

切词器(tokenizer)

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

词项过滤器(token filter)

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

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定义,同义词定义在文件中,可以动态修改
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:正则替换,将符合正则的字符替换成指定字符
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、…
GET _analyze
{
	"analyzer": "standard" ,
	"text":"您的手机号是"
}

自定义分词器

组件定义规则

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

分词器必须在索引中创建,analyzer api使用也必须加上索引名称
在索引中应用分词器:在settings中定义分词器,在mappings中将字段和分词器绑定,query.match全文检索时,自定义分词器生效,而文档查询查的是源数据,不变
analyzer和search_analyzer

  • 前者是源数据的分词器,后者是搜索词的分词器
  • 后者未指定时,默认等于前者
  • 都未指定时,都为standard分词器
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"
}
PUT idx{
		mappings:{
  	properties:{
    	"title":{
      	"type":"text",
      	"analyzer":"my_analyzer",
      	"search_analyzer":"my_search_analyzer"
      }
    }
  }
}

文档归一化器(normalizer)

大小写统一,时态转换,停用词(语气词、介词在大多数场景下无搜索意义)
作用:增加召回率,减少匹配次数

  • 和分词器类似,也有字符过滤器和词项过滤器,但没有切词器
  • 只能用于keyword类型的字段
  • 不能被分词
  • 搜索词也会使用字段的normalizer,不会分词
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

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

PUT goods
{
	mappings:
  	_source:
    	excludes:[]//定义mappings时,定义查询结果只要哪些字段
    	includes:[]
}
GET goods/_search
{
	"_source":{
  	"includes":["name","tags"]//查询结果只包含哪些字段
  	"excludes":[]//查询结果排除哪些字段
  }
}
GET goods/_search
{
	"_source":{
  	"includes":"*"//支持通配符,t*
  	"excludes":[]//查询结果排除哪些字段
  }
}
  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值