ElasticSearch索引管理

原创不易,转载请注明出处。谢谢!

创建索引

迄今为止,我们简单的通过添加一个文档的方式创建了一个索引。这个索引使用默认设置,新的属性通过动态映射添加到分类中。现在我们需要对这个过程有更多的控制:我们需要确保索引被创建在适当数量的分片上,在索引数据 之前 设置好分析器和类型映射。

为了达到目标,我们需要手动创建索引,在请求中加入所有设置和类型映射,如下所示:

PUT /my_index

{

    "settings": { ... any settings ... },

    "mappings": {

        "type_one": { ... any mappings ... },

        "type_two": { ... any mappings ... },

        ...

    }

}

事实上,你可以通过在 config/elasticsearch.yml 中添加下面的配置来防止自动创建索引。

action.auto_create_index: false  将其改为false,即可防止自动创建索引

删除一个索引

用以下的请求来 删除索引:

DELETE /my_index

你也可以这样删除多个索引:  DELETE /index_one,index_two                   DELETE /index_*

你甚至可以这样删除 全部 索引:  DELETE /_all                   DELETE /*

对一些人来说,能够用单个命令来删除所有数据可能会导致可怕的后果。如果你想要避免意外的大量删除, 你可以在你的 elasticsearch.yml 做如下配置:

action.destructive_requires_name: true

这个设置使删除只限于特定名称指向的数据, 而不允许通过指定 _all 或通配符来删除指定索引库。

索引设置

Elasticsearch 提供了优化好的默认配置。 除非你理解这些配置的作用并且知道为什么要去修改,否则不要随意修改。

下面是两个 最重要的设置:

number_of_shards  每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。

number_of_replicas  每个主分片的副本数,默认值是 1 。这个配置可以随时修改。

我们可以创建只有 一个主分片,没有副本的小索引:

然后,我们可以用 update-index-settings API 动态修改副本数:

配置分析器

第三个重要的索引设置是 analysis 部分, 用来配置已存在的分析器或针对你的索引创建新的自定义分析器。

分词与分词器 ,我们介绍了一些内置的 分析器,用于将全文字符串转换为适合搜索的倒排索引。

创建一个自定义分析器

我们可以在 analysis 下的相应位置设置字符过滤器、分词器和词单元过滤器:

PUT /my_index

{

    "settings": {

        "analysis": {

            "char_filter": { ... custom character filters ... },

            "tokenizer": { ... custom tokenizers ... },

            "filter": { ... custom token filters ... },

             "analyzer": { ... custom analyzers ... }

        }

    }

}

创建一个自定义分析器,这个分析器可以做到下面的这些事:

1. 使用 html清除 字符过滤器移除HTML部分。

2. 使用一个自定义的 映射 字符过滤器把 & 替换为 " and " :

3. 使用 标准 分词器分词。

4. 小写词条,使用 小写 词过滤器处理。

5. 使用自定义 停止 词过滤器移除自定义的停止词列表中包含的词:“a”,"the"

类型和映射

类型 在 Elasticsearch 中表示一类相似的文档。 类型由 名称 映射 组成。

映射, 就像数据库中的 schema ,描述了文档可能具有的字段或 属性 、 每个字段的数据类型—比如 keyword, integer 或 date —以及Lucene是如何索引和存储这些字段的。

类型可以很好的抽象划分相似但不相同的数据。但由于 Lucene 的处理方式,类型的使用有些限制。

Lucene 如何处理文档

在 Lucene 中,一个文档由一组简单的键值对组成。 每个字段都可以有多个值,但至少要有一个值。 类似的,一个字符串可以通过分析过程转化为多个值。Lucene 不关心这些值是字符串、数字或日期--所有的值都被当做 不透明字节

当我们在 Lucene 中索引一个文档时,每个字段的值都被添加到相关字段的倒排索引中。你也可以将未处理的原始数据 存储 起来,以便这些原始数据在之后也可以被检索到。

类型是怎么实现的

Elasticsearch 类型是在这个简单基础上实现的。一个索引可能包含多个类型,每个类型有各自的映射和文档,保存在同一个索引中。

Lucene 没有文档类型的概念,每个文档的类型名被存储在一个叫 _type 的元数据字段上。当我们要检索某个类型的文档时, ES 通过在 _type 字段上使用过滤器来限制只返回这个类型的文档。

Lucene 也没有映射的概念。 映射是 Elasticsearch 将复杂 JSON 文档 映射 成 Lucene 需要的扁平化数据的方式。

技术上讲,多个类型可以在相同的索引中存在,只要它们的字段不冲突。

类型不适合 完全不同类型的数据 。如果两个类型的字段集是互不相同的,这就意味着索引中将有一半的数据是空的(字段将是 稀疏的 ),最终将导致性能问题。在这种情况下,最好是使用两个单独的索引。

根对象

映射的最高一层被称为 根对象 ,它可能包含下面几项:

  1. 一个 properties 节点,列出了文档中可能包含的每个字段的映射
  2. 各种元数据字段,它们都以一个下划线开头,例如 _type 、 _id 和 _source
  3. 设置项,控制如何动态处理新的字段,例如 analyzer 、 dynamic_date_formats(动态日期格式) 和 dynamic_templates(动态模板)
  4. 其他设置,可以同时应用在根对象和其他 object 类型的字段上,例如 enabled 、 dynamic 和 include_in_all

属性

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

type: 字段的数据类型,例如 string 或 date

index:字段是否应当被当成全文来搜索( analyzed ),或被当成一个准确的值( not_analyzed ),还是完全不可被搜索( no )

analyzer:确定在索引和搜索时全文字段使用的 analyzer

元数据

_source字段:

默认地,Elasticsearch 在 _source 字段存储代表文档体的JSON字符串。和所有被存储的字段一样, _source 字段在被写入磁盘之前先会被压缩。

这个字段的存储几乎总是我们想要的,因为它意味着下面的这些:

  1. 搜索结果包括了整个可用的文档——不需要额外的从另一个的数据仓库来取文档。
  2. 如果没有 _source 字段,部分 update 请求不会生效。
  3. 当你的映射改变时,你需要重新索引你的数据,有了_source字段你可以直接从Elasticsearch这样做,而不必从另一个(通常是速度更慢的)数据仓库取回你的所有文档。
  4. 当你不需要看到整个文档时,单个字段可以从 _source 字段提取和通过 get 或者 search 请求返回。
  5. 调试查询语句更加简单,因为你可以直接看到每个文档包括什么。

然而,存储 _source 字段的确要使用磁盘空间。如果上面的原因对你来说没有一个是重要的,你可以用下面的映射禁用 _source 字段:

PUT /my_index

{

    "mappings": {

        "my_type": {

             "_source": {

                    "enabled": false

             }

        }

    }

}

_all 字段

轻量 搜索 中,我们介绍了 _all 字段:一个把其它字段值 当作一个大字符串来索引的特殊字段。 query_string 查询子句(搜索 ?q=john )在没有指定字段时默认使用 _all 字段。

_all 字段在新应用的探索阶段,当你还不清楚文档的最终结构时是比较有用的。你可以使用这个字段来做任何查询,并且有很大可能找到需要的文档:

如果你不再需要 _all 字段,你可以通过下面的映射来禁用:

PUT /my_index/_mapping/my_type{

   "my_type": {

         "_all": { "enabled": false }

   }

}

记住,_all 字段仅仅是一个 经过分词的 string 字段。它使用默认分词器来分析它的值,不管这个值原本所在字段是否指定了其他的分词器。

文档标识

文档标识与四个元数据字段 相关:

_id: 文档的 ID 字符串

_type: 文档的类型名

_index: 文档所在的索引

_uid: _type 和 _id 连接在一起构造成 type#id

默认情况下, _uid 字段是被存储(可取回)和索引(可搜索)的。 _type 字段被索引但是没有存储, _id 和 _index 字段则既没有被索引也没有被存储,这意味着它们并不是真实存在的。

尽管如此,你仍然可以像真实字段一样查询 _id 字段。Elasticsearch 使用 _uid 字段来派生出 _id 。 虽然你可以修改这些字段的 index 和 store 设置,但是基本上不需要这么做。

动态映射

当一个字段没有在之前设定好的类型映射中时,ES会通过动态映射来确定字段的数据类型,且自动将该字段添加到类型映射中。

有时这是很理想的行为,但有时却不是。特别是当你使用ES作为主数据源时,更希望遇到未知字段时能抛出一个异常来警示你。

幸运的是,ES可以通过dynamic(动态设置)设置来控制这些行为,它接受以下几个选项:

true:自动添加字段        false:忽略未知字段     strict:当遇到未知字段时,抛出异常   

dynamic 设置可以用在根对象或任何 object 对象上。你可以将 dynamic 默认设置为 strict ,而在特定内部对象上启用它:

自定义动态索引

如果你想在运行时的增加新的字段,你可能会开启动态索引。虽然有时动态映射的 规则 显得不那么智能,幸运的是我们可以通过设置来自定义这些规则。

日期检测

当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2014-01-01 。如果它看起来像一个日期,这个字段会被作为 date 类型添加,否则,它会被作为 string 类型添加。有些时候这个规则可能导致一些问题。

想象你有一个文档长这样:{ "note": "2014-01-01" }

假设这是第一次见到 note 字段,它会被添加为 date 字段,但是如果下一个文档像这样:

{ "note": "Logged out" }

这显然不是一个日期,但为时已晚。这个字段已经被添加为日期类型,这个 不合法的日期 将引发异常。日期检测可以通过在根对象上设置 date_detection 为 false 来关闭:

PUT /my_index{

    "mappings": {

        "my_type": {

             "date_detection": false

        }}}

使用这个映射,字符串将始终是 string 类型。假如你需要一个 date 字段,你得手动添加它。

动态模板

使用 dynamic_templates ,你可以完全控制新字段的映射,你设置可以通过字段名或数据类型应用一个完全不同的映射。

每个模板都有一个名字用于描述这个模板的用途,一个 mapping 字段用于指明这个映射怎么使用,和至少一个参数(例如 match )来定义这个模板适用于哪个字段。

例如,我们给 string 类型字段定义两个模板:

• es : 字段名以 _es 结尾需要使用 spanish 分析器。

• en : 所有其他字段使用 english 分析器。

我们将 es 模板放在第一位,因为它比匹配所有字符串的 en 模板更特殊一点

默认映射

常,一个索引中的所有类型具有共享的字段和设置。用 _default_ 映射来指定公用设置会更加方便,而不是每次创建新的类型时重复操作。 _default 映射像新类型的模板。所有在 _default_ 映射 之后 的类型将包含所有的默认设置,除非在自己的类型映射中明确覆盖这些配置。

_default_ 映射也是定义索引级别的动态模板的好地方。

重建索引

虽然你可以给索引添加新的类型,或给类型添加新的字段,但是你不能添加新的分析器或修改已有字段。假如你这样做,已被索引的数据会变得不正确而你的搜索也不会正常工作。

修改已存在的数据最简单的方法是重新索引:创建一个新配置好的索引,然后将所有的文档从旧的索引复制到新的上。

为了更高效的索引旧索引中的文档,使用【scan-scoll】来批量读取旧索引的文档,然后将通过【bulk API】来将它们推送给新的索引。

你可以在同一时间执行多个重新索引的任务,但是你显然不愿意它们的结果有重叠。所以,可以将重建大索引的任务通过日期或时间戳字段拆分成较小的任务:

假如你继续在旧索引上做修改,你可能想确保新增的文档被加到了新的索引中。这可以通过重新运行重建索引程序来完成,但是记得只要过滤出上次执行后新增的文档就行了。

索引别名

前面提到的重新索引过程中的问题是必须更新你的应用,来使用另一个索引名。索引别名正是用来解决这个问题的!

索引 别名 就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何需要索引名的 API 使用。别名带给我们极大的灵活性,允许我们做到:

• 在一个运行的集群上无缝的从一个索引切换到另一个

• 给多个索引分类(例如, last_three_months )

• 给索引的一个子集创建 视图

现在我们将介绍用它们怎么在零停机时间内从旧的索引切换到新的索引。这里有两种管理别名的途径: _alias 用于单个操作, _aliases 用于原子化多个操作。

我们决定修改索引zhttest中一个字段的映射。当然我们不能修改现存的映射,所以我们需要重新索引数据。下图为当前索引的映射信息:

首先,我们创建有新的映射的索引 zhttest_v2:

然后,我们需要重新索引数据 重新索引数据分为两步:

第一步:通过scroll参数滚动获取来批量读取旧索引的文档:

第二步:通过【bulk API】来将它们推送给新的索引(由于bulk一行代表一条索引信息,通过命令更容易实现,所以在此没有使用页面展示)。

检查新建的索引zhttest_v2,数据是否已经导入:

别名可以指向多个索引,所以我们需要在新索引中添加别名的同时从旧索引中删除它。这个操作需要原子化,所以我们需要用 _aliases 操作:

检查重建索引的结果:

这样,你的应用就从旧索引迁移到了新的,而没有停机时间。而zhttest索引会随着时间推移被删除。

提示:即使你认为现在的索引设计已经是完美的了,当你的应用在生产环境使用时,还是有可能在今后有一些改变的。

所以请做好准备:在应用中使用别名而不是索引。然后你就可以在任何时候重建索引。别名的开销很小,应当广泛使用。

结构化搜索

结构化搜索 是指查询包含内部结构的数据。日期,时间,和数字都是结构化的:它们有明确的格式给你执行逻辑操作。一般包括比较数字或日期的范围,或确定两个值哪个大。

文本也可以被结构化。一包蜡笔有不同的颜色: 红色 , 绿色 , 蓝色 。一篇博客可能被打上 分布式 和 搜索的标签。电子商务产品有商品统一代码(UPCs) 或其他有着严格格式的标识。

通过结构化搜索,你的查询结果 始终 是 是或非;是否应该属于集合。结构化搜索不关心文档的相关性或分数,它只是简单的包含或排除文档。

这在逻辑上是能说通的,因为一个数字不能比其他数字 适合存于某个相同范围。结果只能是:存于范围之中,抑或反之。同样,对于结构化文本来说,一个值要么相等,要么不等。没有 更似 这种概念。

精确值查找

当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。在精确查询时应该尽可能多的使用过滤式查询。

term 查询数字

我们首先来看最为常用的 term 查询, 可以用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text)。

我们来看一下例子,一些产品最初用数字来索引,包含两个字段 price 和 productID :

我们的目标是找出特定价格的产品。在 Elasticsearch DSL 中,我们使用 term 过滤器来实现同样的事。 term 过滤器会查找我们设定的准确值。 term 过滤器本身很简单,它接受一个字段名和我们希望查找的值:

term 过滤器本身并不能起作用。像在【查询 DSL】中介绍的一样,搜索 API 需要得到一个 查询语句 ,而不是一个 过滤器 。为了使用 term 过滤器,我们需要将它包含在一个过滤查询语句中:

转到查询 DSL,我们用 term 过滤器来构造一个类似的查询:

有点出乎意料:我们没有得到任何结果值!为什么呢?问题不在于 term 查询;而在于数据被索引的方式。如果我们使用 analyze API,我们可以看到 UPC 被分解成短小的表征:

所以当我们用 XHDK-A-1293-#fJ3 来查找时,得不到任何结果,因为这个表征不在我们的倒排索引中。相反,那里有上面列出的三个表征。

显然,在处理唯一标识码,或其他枚举值时,这不是我们想要的结果。

为了避免这种情况发生,我们需要通过设置这个字段为 not_analyzed 来告诉 Elasticsearch 它包含一个准确值。这样ES将不会对该字段进行分词,当然要实现这个目标,我们需要重建索引才行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值