elasticsearch中索引的管理

索引管理

我们看到es让开发一个新的应用变得简单,不需要任何预先计划和设置,不过要不了多久
你就会开始想要优化索引和搜索过程,以便更好的适合您的特定用例,这些定制围绕着索引和类型的方方面面
本章介绍管理索引和类型映射的API以及一些重要的设置

创建一个索引

  1. 简单创建一个索引
    PUT /test01
    当我们这样创建一个索引的时候,索引采用的是默认的配置,新的字段通过动态映射的方面添加到类型映射
  • 现在我们需要对建立这个索引的过程做更多的控制,我们想要这个索引有数量适中的主分片
    并且我们在索引任何数据前,分析器和映射已经被建立好
  • 为了达到这个目的我们需要手动创建索引,在请求体里面传入设置和类型映射,
{
    "settings": { ... any settings ... },
    "mappings": {
        "type_one": { ... any mappings ... },
        "type_two": { ... any mappings ... },
        ...
    }
}

注意:我们之后可以使用索引模板来预配置开启自动创建索引,这在索引日志数据时尤其有用
你将日志数据索引在一个以日期结尾的索引上,子夜时分,一个预配置的新索引将会自动创建

删除一个索引

DELETE /my_index

  1. 也可以这样删除多个索引
    DELETE /my_index,myindex2
    DELETE /index_*
  2. 删除全部索引
    DELETE /*
    DELETE /_all

索引设置

  1. es提供了优化好的默认配置,除非你理解了这些配置的作用并且知道为什么要去修改,否则不要随意修改
  • 下面是两个比较重要的设置
    number_of_shards: 每个索引的主分片数,默认值是1,这个配置在索引创建后不能修改
    number_of_replicas: 每个主分片的副本数,默认值是1,对于活动的索引库,这个配置可以随时修改
    例如,我们可已创建一个只有一个主分片,没有副本的小索引
    PUT /my_index
{
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0
    }
}

然后我们可以利用update-index-settings API动态修改副本数,
PUT /my_index/_settings
将刚刚创建的my_index副本数量从0改为1

{
    "number_of_replicas": 1
}

配置分析器

  1. 第三个重要的索引设置是analysis, 用来配置已存在的分析器或者针对你的索引创建新的自定义分析器
    前面介绍了一些内置分析器,用来将全文字符串转换为适合搜索的倒排索引
  • standard分析器适用于全文字段的默认分析器,对于大部分西方语系来说不错
  • standard分词器,通过单词边界分割输入的文本
  • standard语汇单元过滤器,整理分词器触发的语汇单元
  • lowercase语汇单元过滤器,转换所有的语汇单元为小写
  • stop语汇单元过滤器,删除停用词和对搜索相关性影响不大的常用词,如a the and is
  1. 默认情况下,停用词过滤器是被禁用的
    如果需要启动它,你可以通过创建一个基于standard分析器的自定义分析器并设置stopwords参数
    可以给分析器提供一个停用词列表,或者告知使用一个基于特定语义的停用词列表
    下面我们创建一个新的分析器,键es_std,并使用预定义的西班牙停用词列表
{
    "settings": {
        "analysis": {
            "analyzer": {
                "es_std": {
                    "type": "standard",
                    "stopwords": "_spanish_"
                }
            }
        }
    }
}

es_std分析器不是全局的,它仅仅存在于我们定义的spanish_docs索引中,
为了使用analyze API对它进行测试,我们必须使用特定的索引名spanish_docs
GET /spanish_docs/_analyze

{
    "analyzer": "es_std",
    "text": "El veloz zorro marrón"
}

简化的结果已经显示西班牙语停用词El已被正确的移除

自定义分析器

  1. 虽然es带有一些现成的分析器,但是es的强大之处在于你可以自己组合字符串过滤器、分词器、词汇单元过滤器
    来创建自定义的分析器
  2. 一个分析器包含三部分
  • 字符串过滤器
    字符串过滤器用来整理一个尚未被分词的字符串,例如我们的文本是Html格式的,标签div或者p等需要清除掉
    此时我们可以使用html清除 字符过滤器来移除所有的html标签
    一个分析器可以包含0个或多个字符过滤器
  • 分词器
    一个分析器必须有且仅有一个分词器,分词器把字符串分解成单个词条或者词汇单元,标准分析器里面的标准分词器
    把一个字符串按照单词边界分解成单个词条,并且移除大部分的标点符号,当然也有其它不同行为的分词器存在
    例如关键词分词器完整的输出接收到的同样的字符串,空格分词器只根据空格拆分为本,
    正则分词器根据正则表达式来分割文本
  • 词汇单元过滤器
    经过分词后,词单元流会按照顺序经过词汇单元过滤器,词单元过滤器可以添加、修改、删除词单元
    向lowercase和stop词过滤器,但是es里面还有很多词单元过滤器,词干过滤器把词单元遏制为词干
  1. 创建一个自定义分析器
    和我们之前配置es_std分析器一样,我们可以在analysis下配置字符串过滤器、分词器、词汇单元过滤器
    我们来创建一个自定义分析器:
  • 使用html清除 字符过滤器来移除html部分
  • 使用一个自定义的映射 字符过滤器来吧&替换为and
  • 使用标准分词器分词
  • 小写词条,使用小写词过滤器处理
  • 使用自定义停止词过滤器移除自定义的停止词列表中包含的词,
{
    "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"
                    ]
                }
            }
        }
    }
}

索引被创建以后,使用analyze API来测试这个新的分析器
GET /my_index/_analyze

{
    "analyzer": "my_analyzer",
    "text": "a the & ABD <p>12345</p>"
}

分析结果:

{
    "tokens": [
        {
            "token": "and",
            "start_offset": 6,
            "end_offset": 7,
            "type": "<ALPHANUM>",
            "position": 2
        },
        {
            "token": "abd",
            "start_offset": 8,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 3
        },
        {
            "token": "12345",
            "start_offset": 15,
            "end_offset": 20,
            "type": "<NUM>",
            "position": 4
        }
    ]
}

可以看到效果,词单元过滤器中的my_stopwords去掉了a和the词条,字符过滤器中的&_to_and将&替换成了and
内置词汇过滤器lowercase将ABC转换成了abd,内置字符过滤器html_strip将html标签直接去掉了

  • 注意,这个分析器目前是没有多大用处的,除非我们告诉es在哪里用上它,
  • 我们可以像下面这样把该分析器用在text字段上
    PUT /my_index/_mapping
{
    "properties": {
        "title": {
            "type": "text",
            "analyzer": "my_analyzer",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        }
    }
}

然后我们使用analyze API接口测试一下我们新建的分析器如何
GET /my_index/_analyze/

{
    "field": "title",
    "text": "中国我爱你, & <p>the</p> aBB"
}

返回结果

{
    "tokens": [
        {
            "token": "中国",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "我爱你",
            "start_offset": 2,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "爱你",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "abb",
            "start_offset": 20,
            "end_offset": 23,
            "type": "ENGLISH",
            "position": 3
        }
    ]
}

自定义分析器很强大啊!

映射

  1. 映射就像数据库中的schema,描述了文档可能具有的字段或者属性,每个字段的数据类型比如integer date bool text等
    以及lucene是如何索引和存储这些字段的
  2. lucene如何处理文档
    lucene中一个文档有简单的键值对组成,当我们在Lucene中索引一个文档时,每个字段的值都被添加到相关字段的倒排索引中去
    lucene也没有映射的概念,映射是es将复杂的json文档映射成lucene需要的扁平化数据的方式
{
  "name": {
    "type": "text",
    "analyzer": "whitespace"
  }
}

name字段的映射可以声明该字段是text类型,并且它的值被索引到name字段的倒排索引之前
需要通过whitespace分词器分析

根对象

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

  1. 一个properties节点列出了文档中可能包含的每个字段的映射
  2. 各种元数据字段例如:_id,_source
  3. 属性:
    type:字段的数据类型例如:text、date
    analyzer: 确定在索引和搜索时,全文字段使用的analyzer
    index: 布尔类型,索引还是不索引(注意:如果是字符串需要跟字段类型keyword配合使用)
{
    "properties": {
        "name": {
            "type": "keyword",
            "index": false
        }
    }
}
  1. 元数据_source字段
    在一个搜索请求体里,如果我们只想要_source中的指定字段,可以这样查询
    GET /us/_search
{
    "query": {
        "match": {
            "tweet": "API"
        }
    },
    "_source": ["date", "tweet"]
}

这些字段值会从_source字段提取和返回,而不是返回整个_source
注意:在es中对个别字段设置存储的方法总不是最优的,整个文档已经被存储为_source字段,
使用_source字段提取你想要的字段才是最好的

动态映射

  1. 当es遇到文档中以前未遇到的字段时,他用dynamic mapping来确定字段的数据类型,
    并自动把新的字段添加到类型映射中去

索引别名和零停机

  1. 前面提到的重建索引的问题就是必须更新应用中的索引名称,索引别名就是用来解决这个问题的
    索引别名就像一个快捷方式或者软连接,可以指向一个或者多个索引,也可以给任何一个需要索引名的API来使用
  • 在运行的集群中可以无缝从一个索引切换到另一个索引
  • 给多个索引分组
  • 给索引的一个子集创建视图
  1. 看一下在零停机下从旧索引切换到新索引
    有两种方式管理别名:_alias用于管理单个操作,_aliases用于执行多个原子操作
    我们假设你有一个应用名叫my_index的索引,事实上my_index是指向真实索引的别名
    真实索引包含一个版本号my_index_v1,my_index_v2
  2. 首先创建索引my_index_v1,然后将别名my_index指向它
PUT /my_index_v1 
PUT /my_index_v1/_alias/my_index 

创建索引my_index_v1,然后将索引别名my_index指向my_index_v1
可以检测这个别名指向哪一个索引
GET //_alias/my_index
或者哪些别名指向这一个索引
GET /my_index_v1/_alias/

两者都会返回同样的结果

{
    "my_index_v1": {
        "aliases": {
            "my_index": {}
        }
    }
}

然后我们决定修改索引中一个字段的映射,当然我们不能修改现存的映射,所以我们必须重新索引数据
首先我们用新映射创建索引my_index_v2
/my_index_v2

{
    "mappings": {
        "properties": {
            "tags": {
                "type": "keyword",
                "index": false
            }
        }
    }
}

然后我们将数据从my_index_v1迁移到my_index_v2,一旦我们确定文档已经被正确的重新索引了,
我们就将别名指向新的索引,一个别名可以指向多个索引,所以我们在添加别名到新的索引时必须从旧的索引中移除掉
这个操作需要原子化,这意味着我们需要使用_aliases操作
POST /_aliases

{
    "actions": [
        {
            "remove": {"index": "my_index_v1", "alias": "my_index"}
        },
        {
            "add": {"index": "my_index_v2", "alias": "my_index"}
        }
    ]
}

你的应用已经在零停机的情况下从旧索引迁移到了新索引了,即使你认为现在的索引已经设计的很完美了,
在生产环境中还是有可能需要做一些修改的

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

参考文档

posted @ 2022-04-22 16:28  专职  阅读(116)  评论(0编辑  收藏  举报