概要

Elasticsearch让索引创建变得非常简单,只要索引一条新的数据,索引会自动创建出来,但随着数据量的增加,我们开始有了索引优化和搜索优化的需求之后,就会发现自动创建的索引在某些方面不能非常完美的适应我们的需求,我们开始考虑手动创建适合我们业务需求的索引。

索引的CRUD

为了更好地贴切我们的业务数据需求,我们开始更精细的管理我们的索引。

创建索引

创建索引的语法示例如下:

PUT /music
{"settings": {"number_of_shards": 3,"number_of_replicas": 1},"mappings": {"children": {"properties": {"name": {"type": "text","fields": {"keyword": {"type": "keyword","ignore_above": 256}}}}}}
}

settings内的参数

  • numberofshards:每个索引的primary shard数量,索引创建后不可修改。
  • numberofreplicas: 每个索引的replica shard的数量,可以随时修改。

mappings内的参数

  • type: 6.3.1版本只允许设置一个type
  • properties:类型映射具体信息,索引文档的字段名称,类型,分词器都在里面指定。

默认Elasticsearch是允许自动创建索引的,生产环境上为了避免自动索引可能出现的隐患,可以禁止自动创建索引,修改elasticsearch.yml配置文件即可:

action.auto_create_index: false

修改索引

可以单独修改setting部分和mapping部分,修改setting部分示例如下:

PUT /music/_settings
{"number_of_replicas": 2
}

如果要修改mapping信息,如给索引新增字段length、likes、content,示例如下:

PUT /music/_mapping/children
{"properties": {"length": {"type": "long"},"likes": {"type": "long"},"content": {"type": "text","fields": {"keyword": {"type": "keyword","ignore_above": 256}}}}
}

删除索引

DELETE /music
DELETE /music,content
DELETE /music*
DELETE /_all
DELETE /*

如上命令均可删除索引,但此操作一定要慎重,反复确认后再操作,误删的后果不可想像,建议删除操作一定要设置操作权限,另外Elasticsearch可以设置只限定索引名称进行删除,不允许通配符或_all删除大量的索引,作如下设置即可:

action.destructive_requires_name: true

误删索引的后果非常严重,请在操作权限上加把锁,宁可麻烦也不要误删。

查看索引信息

GET /music
GET /music/_settings
GET /music/_mapping

三条命令可以查看索引的完整信息,只查setting信息,只查mapping信息。

分词器设置

analysis是索引设置中非常重要的一部分,默认的分词器我们前面有介绍,有兴趣可以翻一下。我们可以为索引单独配置特有的分词器,或者自定义分词器。

修改分词器设置

例如,我们为music索引创建一个新的分词器,叫做music_std,启用英文停用词列表:

PUT /music
{"settings": {"analysis": {"analyzer": {"music_std": {"type": "standard","stopwords": "_english_"}}}}
}

此命令只能在创建时候执行,已经存在的索引执行会报错。

我们对music索引进行分词器测试:

GET /music/_analyze
{"analyzer": "music_std","text": "get up brightly early in the morning"
}

测试结果是"in","the"这两个词已经被正确的移除掉了。

自定义分词器

Elasticsearch对分词器的应用设置得非常灵活,用户可以根据自己的需求灵活定制字符过滤器、分词器、词单元过滤器来创建自定义的分词器。

文档的分词过程包含以下几步:

  • 字符过滤器

对字符串进行预处理,如HTML标签清洗Love --> Love,I & you --> I and you等等。

  • 分词器

把字符串切分成单个的词条,如英文的按空格和标点切分,中文的按词语切分,针对不同的语言,有不同的分词器,有相对简单的标准分词器,也有特别复杂的中文分词器,里面包含了非常复杂的切分逻辑如:

I Love you --> I/Love/you

我和我的祖国 --> 我/和/我的/祖国

  • Token过滤器
    将分词器得到的词条进一步的处理,如改变词条(英文词干提取loves --> love),删除无实际意义的词条(英文的a, and, this,中文的"的","了","吗"),增加词条(补充同义词)

如果我们自定义分词器,可以从这三个组件入手,可以自行替换。我们举一个示例:

PUT /music
{"settings": {"analysis": {"char_filter": {"&_to_and": {"type": "mapping","mappings": ["&=> and"]}},"filter": {"my_stopwords": {"type": "stop","stopwords": ["the", "a"]}},"analyzer": {"my_analyzer": {"type": "custom","char_filter": ["html_strip", "&_to_and"],"tokenizer": "standard","filter": ["lowercase", "my_stopwords"]}}}}
}

上面示例中我们自定义的分词器有如下特点:

  • 字符过滤器:把&转换成and,并加上html_strip处理html文本
  • token过滤器:将"the","a"作为停用词,全部改成小写

我们对这个分词器进行测试:

GET /music/_analyze
{"text": "you & me the love, <a>, HAHA!!","analyzer": "my_analyzer"
}

响应的结果:

{"tokens": [{"token": "you","start_offset": 0,"end_offset": 3,"type": "<ALPHANUM>","position": 0},{"token": "and","start_offset": 4,"end_offset": 5,"type": "<ALPHANUM>","position": 1},{"token": "me","start_offset": 6,"end_offset": 8,"type": "<ALPHANUM>","position": 2},{"token": "love","start_offset": 13,"end_offset": 17,"type": "<ALPHANUM>","position": 4},{"token": "haha","start_offset": 24,"end_offset": 28,"type": "<ALPHANUM>","position": 5}]
}

可以看到,"the"作为停用词被移除了,&变成了"and",html标签移除了,HAHA小写处理后得到haha。

自定义分词器后,如果需要应用在索引上,需要将它绑定到具体的字段上:

PUT /music/_mapping/children
{"properties": {"content": {"type": "text","analyzer": "my_analyzer"}}
}

后面只要有新的文档进行索引,在content字段上都会使用我们自定义的分词器。

映射对象

root object

映射对象信息是一组JSON结构,最顶层的叫根对象(root object),包括内容如下:

  • properties: 索引中每个字段的映射信息。
  • metadata:各种元数据信息,以下划线开头,如id,source,_type。
  • settings:设置项信息,如analyzer。
  • 其他settings:比如includeinall

properties

主要是指文档字段和属性最重要的三个设置:

  • type: 数据类型,如text、date、long等。
  • index: 该字段是否需要全文搜索(analyzed),或精准搜索(not_analyzed)或是不支持搜索(no)。
  • analyzer: 文档索引和搜索时的分词器。

例如节选了以下properties信息:

{"music": {"mappings": {"children": {"properties": {"author": {"type": "text","analyzer": "english"}}}}}
}

_source

source字段存储的内容包含文档的JSON字符串,source字段在写入磁盘前会被压缩。

_source存储的内容才是我们真正关心的数据,我们可以更加方便的完成这些事:

  • 查询的时候可以一次性拿到完整的document,不需要先拿document id,再发送一次请求拿document
  • partial update基于_source实现
  • reindex时,直接基于_source实现,不需要从数据库(或者其他外部存储)查询数据再修改
  • 可以基于_source定制返回field
  • debug query更容易,因为可以直接看到_source

_all

建立索引时将所有field拼接在一起,作为一个all field ,没指定任何field进行搜索时,就是搜索all field,一般轻量搜索中用得比较多。

如果不需要_all field,可以设置成禁用:

PUT /music/_mapping/children
{"_all": {"enabled": false}
}

也可以指定某些field不加入_all field

PUT /music/_mapping/children
{"properties": {"author": {"type": "text","include_in_all": false}}
}

metadata

文档标识主要的几个字段:

  • _id:文档ID
  • _type:类型名称,6.x以后一个索引只会有一个type
  • _index: 文档所在的索引名称

这三个字段是用来标识一个独一无二的文档所在的位置信息,从这三个字段我们基本上可以定位出来该文档存储在哪个shard中。

动态映射

dynamic属性

Elasticsearch索引文档时,如果JSON结构出现新的字段,Elasticsearch会根据dynamic mapping规则来识别字段的数据类型,并自动增加新的字段,如果我们对文档的JSON结构有较严格的规定,这种自动增加字段的行为,就不是我们期望的操作,我们可以为properties设置dynamic属性来决定这种行为:

  • true: 动态添加新的字段
  • false:忽略新的字段
  • strict: 遇到新的字段,抛出异常

这个dynamic参数可以在任何一层的object中使用,如:

PUT /music
{"mappings": {"children": {"dynamic": "strict","properties": {"name": {"type": "text"},"address": {"type": "object","dynamic": "true"}}}}
}

如果children下面遇到新字段,就会抛出异常如果address内部对象中遇到新字段,会动态创建该字段

示例:

# address内部对象增加两个新字段
PUT /music/children/1
{"name":"sunshine","address": {"province": "gd","city": "sz"}
}

创建成功,响应如下:

{"_index": "music","_type": "children","_id": "1","_version": 1,"result": "created","_shards": {"total": 2,"successful": 1,"failed": 0},"_seq_no": 0,"_primary_term": 1
}

# children下直接增加新字段author
PUT /music/children/1
{"name":"sunshine","author":"Johnny Cash"
}

创建失败,报错响应如下:

{"error": {"root_cause": [{"type": "strict_dynamic_mapping_exception","reason": "mapping set to strict, dynamic introduction of [author] within [children] is not allowed"}],"type": "strict_dynamic_mapping_exception","reason": "mapping set to strict, dynamic introduction of [author] within [children] is not allowed"},"status": 400
}

定制dynamic mapping策略

Elasticsearch在运行中遇到新增的字段时,会根据动态映射模板为新的字段定义类型,但字段类型是根据首次遇到的字段值来定义的,可能会出现误判的情况。

我们先举一个反例,假设我们有一个新增的字段remark,里面的内容是"2019-12-17",是一个日期格式的内容,Elasticsearch会把这个note字段设置成日期格式,但remark字段第二条数据过来的却是"Comment Submit",这只是一段文本,remark字段已经是日期格式了,第二条保存就会抛出异常。

针对日期检测,我们可以选择关闭,如下:

PUT /music
{"mappings": {"children": {"date_detection": false}}
}

但我们针对Long类型,Boolean类型的,同样有这种情况,逐一关闭可行性不高,为此我们需要使用动态模板配置。

动态模板

使用动态模板(dynamic template),我们可以通过字段名称或数据类型来应用不同的映射,来定制自己的模板。

例如我们使用字段名称后缀的方式:

PUT /music
{"mappings": {"children": {"dynamic_templates": [{ "en": {"match":              "*_en", "match_mapping_type": "string","mapping": {"type":           "text","analyzer":       "english"}}}]}}
}

这个含义是如果字段以_en结尾,那么类型为text,analyzer为english,否则类型为string,analyzer为standard。

测试内容:

PUT /music/children/1
{"content": "you are my sunshine"
}PUT /music/children/2
{"content_en": "you are my sunshine"
}

理论上content使用standard分词器,4个单词均可被索引到,content_en字段使用english分词器,are作为停用词会被移除掉。

对索引进行搜索可知:

GET /music/children/_search
{"query": {"match": {"content_en": "are"}}
}

结果是空

{"took": 1,"timed_out": false,"_shards": {"total": 5,"successful": 5,"skipped": 0,"failed": 0},"hits": {"total": 0,"max_score": null,"hits": []}
}

使用其他的关键词,或使用content字段,搜索均能出结果,符合预期。

小建议

以上只是动态映射模板的一个小案例,真实生产环境中文档的复杂度远高于此,对文档的结构而言,优先手动创建索引,明确每个字段的含义和数据类型,其次再做通用的动态映射模板,但也需要定时检查索引下的数据类型,以防出现意外情况。

小结

本篇主要介绍索引的相关知识,包含索引的CRUD、自定义分词器、映射对象的知识,最后简单介绍了映射模板的配置,实际生产如果有乃至动态模板配置,肯定远比这个复杂,这里仅作抛砖引玉,谢谢。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

elasticsearch 索引_Elasticsearch系列---索引管理相关推荐

  1. imp 只导入索引_Elasticsearch系列---实战零停机重建索引

    前言 我们使用Elasticsearch索引文档时,最理想的情况是文档JSON结构是确定的,数据源源不断地灌进来即可,但实际情况中,没人能够阻拦需求的变更,在项目的某个版本,可能会对原有的文档结构造成 ...

  2. elasticsearch 文档_ElasticSearch系列04:索引与文档的CURD

    引言:上一节我们学习了ES的数据类型,有同学反馈说,里面的语句看不懂.今天,TeHero就为大家讲解ES索引和文档的CURD的操作.掌握了基本操作才能更好的系统学习,让我们开始吧! 1.索引的CURD ...

  3. ElasticSearch核心基础之索引管理

    一 索引管理 1.1 创建索引 # 建立索引的时候,我们可以设置主分片和备份分片的数量通过setting字段number_of_shards和number_of_replicas字段设置 # 对于ES ...

  4. elasticsearch 主键字段_ElasticSearch 索引 VS MySQL 索引

    来自公众号:crossoverJie链接:https://crossoverjie.top/2020/08/24/elasticsearch/ElasticSearch%20VS%20MySQL/ 前 ...

  5. 深入理解ElasticSearch(八)索引管理

    索引管理 1.创建一个索引 到目前为止, 我们已经通过索引一篇文档创建了一个新的索引 .这个索引采用的是默认的配置,新的字段通过动态映射的方式被添加到类型映射.现在我们需要对这个建立索引的过程做更多的 ...

  6. Elasticsearch入门、Kibana 索引管理(elasticserch-head 插件使用, Kibanan 安装和使用)

    目录 一.搜索的介绍 二.全文检索的介绍 三.ELK日志协议栈 1.ELK协议栈基本介绍 四.Elasticsearch介绍 1.什么是ElasticSearch 2.ElasticSearch使用案 ...

  7. music算法_Elasticsearch系列---相关性评分算法及正排索引

    概要 上一篇中多次提到了按相关性评分,本篇我们就来简单了解一下相关性评分的算法,以及正排索引排序的优势. 评分算法 Elasticsearch进行全文搜索时,Boolean Model是匹配的基础,先 ...

  8. ElasticSearch(二)索引管理

    目录 索引管理 1.创建索引 2.修改索引 3.删除索引 4.获取索引 5.打开和关闭索引 索引映射管理 1.增加映射 不同类型之间的冲突 2.获取映射 3.获取字段映射 4.判断类型是否存在 索引别 ...

  9. Elasticsearch系列-索引的基本操作

    Elasticsearch索引的基本操作 前言 索引基本操作 创建索引 常用数据类型 keyword text 数值类型 boolean date 数组类型 对象类型 nested 地理类型:geo_ ...

最新文章

  1. 嵌入式 linux 进程锁,嵌入式  Linux线程锁详解pthread_mutexattr_t
  2. 二、神兽变变变(上)
  3. 炼丹感悟:On the Generalization of RL
  4. 计算机桌面组成部分教案,计算机基础 教案设计(完整版).doc
  5. mac共享单个磁盘_如何与您的所有设备共享酒店的单个Wi-Fi连接
  6. 602. Friend Requests II: Who Has Most Friend?
  7. [2013.8.29]马甲去重复 c++源码
  8. 我的第一个 RN 项目-趣闻
  9. Purism释出Librem 5智能型手机新进展
  10. nodejs 图片处理模块 rotate_会照片处理的不只是ps,还有python!
  11. Python深度学习:常见优化算法
  12. 使用Fragstats对栅格数据进行分析
  13. mysql数据库字符集实践详解_mysql数据库 详解 之 自学成才1
  14. 3rd Batch请查收!您的问题解答清单
  15. 《AngularJS深度剖析与最佳实践》一2.12 单元测试
  16. 招投标中评标的方法是什么?
  17. Flutter 打开外部第三方应用
  18. 7.27北京 以我的方式纪念环法--香山游击
  19. 前端开发:Vue中v-if和v-show的使用以及应用场景
  20. 【七七八八】coursera python-basis certification

热门文章

  1. 「递归」第6集 | 是鹅厂技术青年的模样
  2. 中国第五届CSS大会分享:CSS TIME
  3. Puppet SaltStack Chef Ansible
  4. Mysql Type中的all和index区别?
  5. npm 安装报错 rollbackFailedOptional verb npm-session无法解决?
  6. leetcode 519. Random Flip Matrix | 519. 随机翻转矩阵(洗牌算法Fisher–Yates shuffle)
  7. 操作系统:第二章 进程管理1 - 进程、线程
  8. 数据结构: 试用判定树的方法给出在中序线索化二叉树上: (1) 如何搜索指定结点的在中序下的后继。 (2) 如何搜索指定结点的在前序下的后继。(3) 如何搜索指定结点的在后序下的后继。
  9. 数据结构:超好用的数据结构与算法可视化工具(USFCA旧金山大学)
  10. 【Docker】在Docker中安装redis、rabbitmq