Elasticsearch系列---索引管理

概要

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内的参数

  • number_of_shards:每个索引的primary shard数量,索引创建后不可修改。
  • number_of_replicas: 每个索引的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标签<a>移除了,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:比如include_in_all

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架构社区
可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术

原文地址:https://www.cnblogs.com/huangying2124/p/12208294.html

时间: 2024-07-30 09:03:34

Elasticsearch系列---索引管理的相关文章

elasticsearch系列二:索引详解(快速入门、索引管理、映射详解、索引别名)

一.快速入门 1. 查看集群的健康状况 http://localhost:9200/_cat http://localhost:9200/_cat/health?v 说明:v是用来要求在结果中返回表头 状态值说明 Green - everything is good (cluster is fully functional),即最佳状态Yellow - all data is available but some replicas are not yet allocated (cluster i

elasticsearch系列三:索引详解(分词器、文档管理、路由详解)

一.分词器 1. 认识分词器  1.1 Analyzer   分析器 在ES中一个Analyzer 由下面三种组件组合而成: character filter :字符过滤器,对文本进行字符过滤处理,如处理文本中的html标签字符.处理完后再交给tokenizer进行分词.一个analyzer中可包含0个或多个字符过滤器,多个按配置顺序依次进行处理. tokenizer:分词器,对文本进行分词.一个analyzer必需且只可包含一个tokenizer. token filter:词项过滤器,对to

[ElasticSearch]Java API 之 索引管理

ElasticSearch为了便于处理索引管理(Indices administration)请求,提供了 org.elasticsearch.client.IndicesAdminClient接口.通过如下代码从 Client 对象中获得这个接口的实现: IndicesAdminClient indicesAdminClient = client.admin().indices(); IndicesAdminClient定义了好几种prepareXXX()方法作为创建请求的入口点. 1. 索引

[Elasticsearch] 索引管理 (一)

索引管理 本文翻译自Elasticsearch官方指南的索引管理(Index Management)一章 我们已经了解了ES是如何在不需要任何复杂的计划和安装就能让我们很容易地开始开发一个新的应用的.但是,用不了多久你就会想要仔细调整索引和搜索过程来更好的适配你的用例. 几乎所有的定制都和索引(Index)以及其中的类型(Type)相关.本章我们就来讨论用于管理索引和类型映射的API,以及最重要的设置. 创建索引 到现在为止,我们已经通过索引一份文档来完成了新索引的创建.这个索引是使用默认的设置

一文带您了解 Elasticsearch 中,如何进行索引管理(图文教程)

欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/essay/about-elasticsearch-index-manage 在 Elasticsearch 中,索引是一个非常重要的概念,它是具有相同结构的文档集合.类比关系型数据库,比如 Mysql, 你可以把它对标看成和库同级别的概念. 今天小哈将带着大家了解, 在 Elasticsearch

MySQL索引管理及执行计划

第1章 索引介绍: 索引是对数据库表中一列或者多了的值进行排序的一种结构,使用索引可以快速访问数据库表中的特定信息,如果想按特定职员的姓名来查找,则与他在表中搜索所有的行相比,索引有助于更快的获取信息 索引的一个主要目的就是加快检索表中的数据的方法,既能协助信息搜索者尽快找到符合限制条件的记录ID的辅助数据结构 1.1 索引的类型介绍: btree:B+树索引    最为常用 hash:hash索引 fulltest:全文索引 rtree:r数索引 第2章 索引管理 2.1 B树索引的分类: 主

第六章 索引管理

图2·B*tree索引 3.索引管理 索引建立在表的列上(字段)的.在where后面的列建立索引才会加快查询速度.pages<---索引(属性)<----查数据. 1.索引分类: 主键索引普通索引*****唯一索引 2.添加索引: #创建索引 alter table test add index index_name(name); #创建索引 create index index_name on test(name); #查看索引 desc table; #查看索引 show index fr

elasticsearch的索引自动清理及自定义清理

近发现elasticsearch近期索引文件大的吓人,清理了下之前的索引文件,发现服务器性能大大的减轻了一半,想一直保留近一个月的索引文件,但是又不想每个月手动清楚,在此写了一个小脚本 一. 手动删除 rm -rf *2016-07-* 二.api删除 curl -XDELETE 'http://127.0.0.1:9200/logstash-2016-07-*' 清理掉了所有 7月份的索引文件,我发现curl 删除比rm删除要快出很多 三.脚本加api删除(推荐) cat es-index-c

Atitit.index&#160;manager&#160;api&#160;design&#160;索引管理api设计

Atitit.index manager api design 索引管理api设计 1. kw1 1.1. 索引类型 unique,normal,fulltxt1 1.2. 聚集索引(clustered index,也称聚类索引1 1.3. 索引方式:btree,hashtable2 1.4. 索引使用所有的页面规模百分比2 2. Ui2 3. api2 3.1. createIndex(indexName,cols)2 3.2. Rebuild2 3.3. Del2 3.4. Up2 4. -