本随记内容不足以完全应对ElasticSearch开发环境各种突发情况,只是根据自己的学习进度对日常工作可能遇到的问题的总结与归纳,仅供参考。
PS:以下所提供的各种文档或问题解决思路其实官方文档都有,所以有困难检索官方文档绝对没问题,前提是看得懂英文。
ElasticSearch的安装网上教程千篇一律,这里就不再进行过多的阐述了。推荐官方民间翻译文档以供参考:
Elasticsearch中文文档 -安装 Elasticsearch
Linux系统里面推荐使用docker进行安装,方便后续维护。在进行docker安装时需要将elasticsearch目录下的config文件夹,data文件夹,plugins文件夹映射到服务器的外部目录下,方便后续的维护和修改。
Kibana是 Elastic 产品集的窗口,可以更方便直观操作命令。你可以把它理解成数据库管理工具Navicat。
Kibana的安装也不进行详细说明,同样贴个几个文档以供参考:
官方文档-安装Kibana
Kibana配置参数概述
index 类似于传统关系数据库中的一个数据库 ,是一个存储关系型文档的地方。
每个 index 可以包含多个 type,这里的 type 类似于传统关系数据库中的 表。
mapping 是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等。 所以一个根据实际情况进行合理设计的 mapping 会大大提高查询效率和性能。
field 相当于是数据表的字段,用于标记区分文档数据不同的属性。
不同的 type 存储着各自的多个 document,document 类似于传统关系数据库中的数据。document 的字段受 mapping 和 field 的规则限制。
如果新增一个 document 包含了 mapping 不曾定义的一个新的 field ,ElasticSearch会默认在mapping 添加当前属性的 field 信息。虽然这种操作很方便,但是还是建议根据实际情况进行合理的 mapping 构建
routing 是一个可变值,默认是 document 的_id,也可以是自定义的值。通过公式 shard = hash(routing) % number_of_primary_shards
可以计算出当前 document 储存在哪个分片上。
ElasticSearch的操作遵循Restful风格,并且数据都是以json格式表示
index json下有3种属性:
aliases: 索引别名
过滤器和路由
elasticsearch Routing 路由详解
{
"aliases": {
"test_index_ali1": {},
"test_index_ali2": {
//过滤器,匹配字段过滤,查询当前别名的文档时,只有匹配的字段才可以查询出来
"filter": {},
//分配索引储存的路由,保存文档的时候会默认储存在当前分片下
"index_routing": "1",
//分配索引查询的路由,查询的时候只能查询到当前分片下的文档
"search_routing": "1,2",
//综合index_routing 和 search_routing的共同用法
"routing": "1"
}
}
}
mapping: 映射,类似于表结构设计
Elasticsearch 评分score计算中的Boost 和 queryNorm
{
"mappings": {
"properties": {
//字段名
"title": {
//字段类型
"type": "text",
//分析器
"analyzer": "ik_smart",
//评分系数
"boost": 1
}
}
}
}
setting: 当前索引的配置包括:分片数,副本数,刷新间隔,分析器
{
"settings":{
// 设置索引分片数,默认为1,只能在创建索引时设置,之后任何时候都不能修改
"number_of_shards": 1,
// 设置索引分片副本数,默认为1,之后可以任意修改
"number_of_replicas": 1,
// 刷新间隔,默认1s
"refresh_interval": "1s",
// 分析器
"analysis":{
//分析器
"analyzer": {
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer"
}
},
//三者顺序:Character Filters--->Tokenizer--->Token Filter
//三者个数:analyzer = CharFilters(0个或多个) + Tokenizer(恰好一个) + TokenFilters(0个或多个)
//字符过滤器
"char_filter": {},
//Token过滤器,将切分的单词进行加工
"filter": {},
//分词器
"tokenizer": {}
}
}
}
使用ElasticSearch进行数据查询时需要注意以下几点:
es内置了许多分词器,常用的有:
除此之外,推荐一个第三方的分词器 IK分词器,可以用来切分中文信息。但是除了它配置里面内置的一些词库,有些生僻字或者非常用词语需要自行学习添加,不一定适用所有关键字查询
如何知道所使用的分词器对需要查询的关键字怎么进行分词的?是否是你想要的结果?可以使用如下查询
GET _analyze
{
"analyzer": "ik_max_word",
"text" : "Beauty & Healthy"
}
查询某个字段里含有某个关键词的文档,它并不知道分词器的存在,这种查询适合keyword、numeric、date等明确值的
ES引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变
Bool查询对应Lucene中的BooleanQuery,它由一个或者多个子句组成,每个子句都有特定的类型。
返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match参数定义了至少满足几个子句。
返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值
默认排序规则是用es评分倒序排序的,可以自定义其他排序规则。
IK分词器属于第三方插件,需要自行安装。下载安装包,解压到plugins目录下,重启es即可使用。
IK分词器是根据其内部词库分词的,其内置的词库不一定能完全匹配日常用语,所以可以通过配置文件IKAnalyzer.cfg自行丰富其词库:
本地扩展词库修改后需要重启es才能生效;远程词库可以进行热更新。
IK中文分词器远程字典设置+热更新
中文分词可以用ik分词器解决,但是当查询英文文本进行分词的时候并不能很好命中关键字。举个例子:
现在有个文档name属性的值为Beauty & Healthy,用常规分词器或者ik分词器 使用analyze分析下
可以发现,只有你搜索beauty 或者 healthy 的时候才可以将这条数据查询出来。但有时需要做搜索推荐的时候,可能我们只希望搜索be 或这 b 或者 eau 这种关键字的就能将这条数据带出来,那么已知的常规分词器暂时无法实现这种功能,这个时候就推荐使用edge_ngram 或者 ngram分词器。
这两个分词器需要在创建index的时候去自定义一些常规参数才能正常使用。下面以ngram分词器举例
PUT test_index
{
"settings": {
//NGramTokenizer和NGramTokenFilter的min_gram和max_gram之间允许的最大差异。默认为1。,必须要加,不然会报错
"index.max_ngram_diff": 4,
"analysis": {
"analyzer": {
//声明分词器
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer"
}
},
"tokenizer": {
//定义ngram的参数
"ngram_tokenizer": {
"type": "ngram",
//分词后词语的最小长度
"min_gram": 1,
//分词后词语的最大长度
"max_gram": 4,
//设置分词的形式,例如,是数字还是文字。elasticsearch将根据分词的形式对文本进行分词。
"token_chars": [
"letter",
"digit"
]
}
}
}
}
}
返回结果
{
"tokens" : [
{
"token" : "B",
"start_offset" : 0,
"end_offset" : 1,
"type" : "word",
"position" : 0
},
{
"token" : "Be",
"start_offset" : 0,
"end_offset" : 2,
"type" : "word",
"position" : 1
},
{
"token" : "Bea",
"start_offset" : 0,
"end_offset" : 3,
"type" : "word",
"position" : 2
},
{
"token" : "Beau",
"start_offset" : 0,
"end_offset" : 4,
"type" : "word",
"position" : 3
},
{
"token" : "e",
"start_offset" : 1,
"end_offset" : 2,
"type" : "word",
"position" : 4
},
{
"token" : "ea",
"start_offset" : 1,
"end_offset" : 3,
"type" : "word",
"position" : 5
},
{
"token" : "eau",
"start_offset" : 1,
"end_offset" : 4,
"type" : "word",
"position" : 6
},
{
"token" : "eaut",
"start_offset" : 1,
"end_offset" : 5,
"type" : "word",
"position" : 7
},
{
"token" : "a",
"start_offset" : 2,
"end_offset" : 3,
"type" : "word",
"position" : 8
},
{
"token" : "au",
"start_offset" : 2,
"end_offset" : 4,
"type" : "word",
"position" : 9
},
{
"token" : "aut",
"start_offset" : 2,
"end_offset" : 5,
"type" : "word",
"position" : 10
},
{
"token" : "auty",
"start_offset" : 2,
"end_offset" : 6,
"type" : "word",
"position" : 11
},
{
"token" : "u",
"start_offset" : 3,
"end_offset" : 4,
"type" : "word",
"position" : 12
},
{
"token" : "ut",
"start_offset" : 3,
"end_offset" : 5,
"type" : "word",
"position" : 13
},
{
"token" : "uty",
"start_offset" : 3,
"end_offset" : 6,
"type" : "word",
"position" : 14
},
{
"token" : "t",
"start_offset" : 4,
"end_offset" : 5,
"type" : "word",
"position" : 15
},
{
"token" : "ty",
"start_offset" : 4,
"end_offset" : 6,
"type" : "word",
"position" : 16
},
{
"token" : "y",
"start_offset" : 5,
"end_offset" : 6,
"type" : "word",
"position" : 17
},
{
"token" : "H",
"start_offset" : 9,
"end_offset" : 10,
"type" : "word",
"position" : 18
},
{
"token" : "He",
"start_offset" : 9,
"end_offset" : 11,
"type" : "word",
"position" : 19
},
{
"token" : "Hea",
"start_offset" : 9,
"end_offset" : 12,
"type" : "word",
"position" : 20
},
{
"token" : "Heal",
"start_offset" : 9,
"end_offset" : 13,
"type" : "word",
"position" : 21
},
{
"token" : "e",
"start_offset" : 10,
"end_offset" : 11,
"type" : "word",
"position" : 22
},
{
"token" : "ea",
"start_offset" : 10,
"end_offset" : 12,
"type" : "word",
"position" : 23
},
{
"token" : "eal",
"start_offset" : 10,
"end_offset" : 13,
"type" : "word",
"position" : 24
},
{
"token" : "ealt",
"start_offset" : 10,
"end_offset" : 14,
"type" : "word",
"position" : 25
},
{
"token" : "a",
"start_offset" : 11,
"end_offset" : 12,
"type" : "word",
"position" : 26
},
{
"token" : "al",
"start_offset" : 11,
"end_offset" : 13,
"type" : "word",
"position" : 27
},
{
"token" : "alt",
"start_offset" : 11,
"end_offset" : 14,
"type" : "word",
"position" : 28
},
{
"token" : "alth",
"start_offset" : 11,
"end_offset" : 15,
"type" : "word",
"position" : 29
},
{
"token" : "l",
"start_offset" : 12,
"end_offset" : 13,
"type" : "word",
"position" : 30
},
{
"token" : "lt",
"start_offset" : 12,
"end_offset" : 14,
"type" : "word",
"position" : 31
},
{
"token" : "lth",
"start_offset" : 12,
"end_offset" : 15,
"type" : "word",
"position" : 32
},
{
"token" : "lthy",
"start_offset" : 12,
"end_offset" : 16,
"type" : "word",
"position" : 33
},
{
"token" : "t",
"start_offset" : 13,
"end_offset" : 14,
"type" : "word",
"position" : 34
},
{
"token" : "th",
"start_offset" : 13,
"end_offset" : 15,
"type" : "word",
"position" : 35
},
{
"token" : "thy",
"start_offset" : 13,
"end_offset" : 16,
"type" : "word",
"position" : 36
},
{
"token" : "h",
"start_offset" : 14,
"end_offset" : 15,
"type" : "word",
"position" : 37
},
{
"token" : "hy",
"start_offset" : 14,
"end_offset" : 16,
"type" : "word",
"position" : 38
},
{
"token" : "y",
"start_offset" : 15,
"end_offset" : 16,
"type" : "word",
"position" : 39
}
]
}
Tokenizer常用用法
自定义ngram分词器
edge_ngram 和 ngram的区别
常规排序里距离排序占了很大的分量,这里参考官方文档即可。
按距离排序
springboot中使用ElasticSearch的详细教程