Elasticsearch索引定义

发布于:2024-05-04 ⋅ 阅读:(36) ⋅ 点赞:(0)

1. 前言

索引是具有相同结构的文档的集合,每个索引都拥有一个唯一的索引名称,它是ES里面非常重要的概念。一个ES集群中可以有多个索引,不同的索引代表不同的业务类型数据。

什么时候需要创建新的索引呢?一般来说有两类场景:

  • 按业务分类:比如存储新闻数据的索引news、存储日志的索引logs等。
  • 按日期范围分类:当数据量特别大时,可以根据时间范围创建索引,例如面对海量的线上日志,可以根据月份来创建日志索引:logs-202401、logs-202402等等。

索引的命名需要遵循以下约束:

  • 只能使用小写字母,不能使用大写字母
  • 不能包括 \ / * ? ” < > | ` # : 及空格等特殊符号
  • 不能以 - _ + 作为开始字符
  • 不能命名为“.”或者“…”
  • 不能超过255个字节
  • 不建议使用中文命名

2. 索引定义

在索引文档前,首先需要定义索引。包括:索引名称、索引设置、索引映射、别名、分析器等。
如下示例,我们创建了一个名称为“student”的索引,它拥有1个分片数和1个副本数;在索引映射里我们定义了三个字段分别是:学号 student_id、姓名 name、性别 gender,字段类型都是keyword,用于精准匹配;同时该索引还有一个别名:student_alias。

PUT student
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "student_id": {
        "type": "keyword"
      },
      "name": {
        "type": "keyword"
      },
      "gender": {
        "type": "keyword"
      }
    }
  },
  "aliases": {
    "student_alias": {}
  }
}

2.1 索引设置

索引设置可以分为两大类:静态设置和动态设置。

静态设置:只允许在创建索引时或者针对已关闭的索引进行设置,例如:

  • index.number_of_shards:索引拥有的主分片数,默认值为1,上限是1024,创建后不能修改
  • index.codec:索引压缩算法,默认使用LZ4算法,可以指定best_compression 以获得更高的压缩比

动态设置:可以借助更新设置API的方式进行动态更新,更新后立即生效,例如:

  • index.number_of_replicas:主分片拥有的副本分片数
  • index.refresh_interval:refresh操作的频率,决定了文档写入后多久可以被搜索到,默认1s
  • index.max_result_window:搜索结果的窗口大小,默认值10000,调大该值可能会影响ES性能

2.2 索引映射

索引映射可以理解为数据库表结构Schema,通过index.mappings 属性设置。索引映射的内容包含:字段名称、字段类型、分析器的定义(针对text类型)、fielddata、doc_values等设置。
如下示例,定义“news”索引用来存放新闻数据,标题title数据类型是text,使用「ik_max_word」分词器、内容content数据类型也是text,使用「ik_smart」分词器。

PUT news
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_smart"
      }
    }
  }
}

2.3 索引别名

索引创建后,索引名称就不支持修改了,但是可以通过设置别名来满足不同的业务,ES的大部分API都可以通过索引别名来调用。

比如,面对线上海量的日志数据,一般会根据日志的时间写入到不同的索引,比如按年、按月、甚至按天来创建索引,但是对外提供的检索服务一般会按照相对时间来查询日志,比如查询近一个月的日志,此时程序要查询的索引名称会随着时间不断变化,我们就可以创建一个索引别名“logs_last_month”来指向最近一个月的所有索引。
如下示例,索引别名“logs_last_month”从"logs_202402" 指向了 “logs_202403”。

POST _aliases
{
  "actions": [
    {
      "remove": {
        "index": "logs_202402",
        "alias": "logs_last_month"
      }
    },
    {
      "add": {
        "index": "logs_202403",
        "alias": "logs_last_month"
      }
    }
  ]
}

2.4 索引模板

索引模板是一种告诉Elasticsearch在创建索引时如何配置索引的方法。

试想这样一个场景,面对线上海量的日志,需要按照月份来创建多个日志索引,如何保证日志索引之间的配置是一样的呢?即拥有相同的settings、mappings等配置。
使用相同的配置来创建索引固然是一种方案,但是太繁琐了,索引模板应运而生。
Elasticsearch7.8版本之后开始支持两种索引模板类型:普通索引模板和组件索引模板。

2.4.1 普通索引模板

普通索引模板就是预先创建好的一个完整的索引模板,ES在创建索引时,如果发现可以匹配到索引模板,就会采用模板设置。
如下命令会创建一个普通索引模板,它会匹配”logs-*“的索引名称,索引映射字段和数据类型都已指定。

PUT _index_template/logs_template
{
  "index_patterns": [
    "logs-*"
  ],
  "template": {
    "mappings": {
      "properties": {
        "trace_id": {
          "type": "keyword"
        },
        "content": {
          "type": "text"
        },
        "time": {
          "type": "date"
        }
      }
    }
  }
}

现在我们创建一个”logs-2024“索引,会发现它成功应用到了上述模板的配置。

PUT logs-2024
GET logs-2024

{
  "logs-2024": {
    "aliases": {},
    "mappings": {
      "properties": {
        "content": {
          "type": "text"
        },
        "time": {
          "type": "date"
        },
        "trace_id": {
          "type": "keyword"
        }
      }
    }
    ......
  }
}

2.4.2 组件索引模板

组件模板的核心在于将原有普通模板定义的mappings、settings等配置以组件的方式分隔,以便最小化更新模板。

如下示例,定义settings组件:主分片数和副本分片数均为1,refresh时间间隔是5s,采用best_compression压缩方式

PUT _component_template/mylogs-settings
{
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "refresh_interval": "5s",
      "codec": "best_compression"
    }
  }
}

如下示例,定义mappings组件,包含三个字段

PUT _component_template/mylogs-mappings
{
  "template": {
    "mappings": {
      "properties": {
        "trace_id": {
          "type": "keyword"
        },
        "content": {
          "type": "text"
        },
        "time": {
          "type": "date"
        }
      }
    }
  }
}

最后就是基于组件模板来定义索引模板,如下示例,效果和直接定义普通索引模板是一样的

PUT _index_template/logs-template-for-components
{
  "index_patterns": [
    "logs-*"
  ],
  "priority": 10, 
  "composed_of": [
    "mylogs-settings",
    "mylogs-mappings"
  ]
}

2.4.3 动态模板

动态模板允许我们更好地控制ES如何在默认的动态字段映射规则之外映射数据。通过将index.mappings.dynamic 设置为true或runtime,可以启用动态映射,当我们索引一个原先不存在的字段时,ES会动态的新增映射字段。但是有些时候,ES动态映射规则不是很理想,例如ES会把整型默认映射为long类型,占用8个字节,如果我们不需要这么大的范围就很浪费空间,就可以通过动态模板来调整ES的映射规则。

ES动态模板支持的匹配条件:

  • match_mapping_type | unmatch_mapping_type:匹配或没匹配到指定的数据类型
  • match | unmatch:模式匹配或没匹配到指定的字段名称
  • path_match | path_unmatch:匹配或没匹配到字段的路径

如下示例,创建了一个动态模板,第一条规则是把string类型且以"ip"结尾的字段映射为ip类型;第二条规则是把string类型且以"_date"结尾的字段映射为date类型。

PUT _index_template/my-dynamic-template
{
  "index_patterns": [
    "index-dynamic-*"
  ],
  "template": {
    "mappings": {
      "dynamic_templates": [
        {
          "string_as_ip": {
            "match_mapping_type": "string",
            "match": "*ip",
            "mapping": {
              "type": "ip"
            }
          }
        },
        {
          "string_as_date": {
            "match_mapping_type": "string",
            "match": "*_date",
            "mapping": {
              "type": "date"
            }
          }
        }
      ]
    }
  }
}

我们创建一个索引,让它能应用到动态模板。接着往里面索引一个文档,查看索引映射,发现字段数据类型符合预期。

PUT index-dynamic-01
POST index-dynamic-01/_doc
{
  "node-ip":"127.0.0.1",
  "create_date":"2024-01-01T00:00:00"
}

GET index-dynamic-01
{
  "index-dynamic-01": {
    "mappings": {
      "properties": {
        "create_date": {
          "type": "date"
        },
        "node-ip": {
          "type": "ip"
        }
      }
    }
  }
}

但是,如果索引一个非法的文档,例如字符串不是日期格式的,ES就会报错:

POST index-dynamic-01/_doc
{
  "xx_date":"haha"
}

{
  "error": {
    "root_cause": [
      {
        "type": "document_parsing_exception",
        "reason": "[2:13] failed to parse field [xx_date] of type [date] in document with id '1-trmI4BODFb3LbQXXSd'. Preview of field's value: 'haha'"
      }
    ],
    "type": "document_parsing_exception",
    "reason": "[2:13] failed to parse field [xx_date] of type [date] in document with id '1-trmI4BODFb3LbQXXSd'. Preview of field's value: 'haha'",
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "failed to parse date field [haha] with format [strict_date_optional_time||epoch_millis]",
      "caused_by": {
        "type": "date_time_parse_exception",
        "reason": "Failed to parse with all enclosed parsers"
      }
    }
  },
  "status": 400
}

网站公告

今日签到

点亮在社区的每一天
去签到