ElasticSearch的REST APIs 之 索引的mapping管理

原创
2021/10/21 18:00
阅读数 487

基于ES 7.7

包括4个api: Put mapping, Get mapping, Get field mapping, Type exists(7.0.0已废弃)

1. 设置/Put mapping

给已现有的索引添加字段, 或者修改现有字段的搜索设置(search settings)。官方文档

#设置单个索引
PUT /<index_name>/_mapping

# 同时设置多个索引(使用同样的mapping)
PUT /<index_name,index_name2>/_mapping

# 更新所有索引: 可以忽略索引名称, 或者使用参数 `_all`
PUT /_all/_mapping
PUT /_maping

查询参数

allow_no_indices

当没有匹配的索引时,是否正常返回数据(否则抛出错误)。

如果设置为true, 则当使用通配符(*)、索引别名、_all匹配到的索引不存在(missing)或者已关闭(closed)时,不会抛出错误。

默认false, 表示会抛出错误。

expand_wildcards

通配符查询时可以匹配的索引的条件, 多个值之间以英文逗号分割, 比如"open,hidden"。默认是open。可用的值有:

  • all: 匹配所有open和closed的索引, 包括隐藏的(hidden).
  • open: 默认, 表示只匹配开放中的索引
  • closed: 只匹配关闭的(closed)的索引
  • hidden: 匹配隐藏的(hidden)的索引, 必须和open/closed联合使用. (官方文档说open和closed可以一起用, WAF??)
  • none: 不接受通配符.

ignore_unavailable

如果有索引不存在时是否忽略。

默认false,就是返回404并抛出错误信息。查询时只要有一个索引不存在,则都抛出错误。

master_timeout

连接到master节点的超时时间,默认 30s

timeout

等待返回结果的超时时间,默认 30s

Request Body

*properties

必填, mapping对象。字段的mapping。

如果是一个新的字段,会包含以下映射:

  • 字段名称
  • 字段数据类型
  • mapping的参数

如果是已存在的字段, 则参照本节内容后面的 "如果修改已存在字段的映射".

几个栗子

1. 新建索引时

单个索引:

# 单个索引

## 先建立一个索引, 不带mapping
PUT /publications

## 再定义索引的mapping
PUT /publications/_mapping
{
  "properties": {
    "title":  { "type": "text"}
  }
}

同时给多个索引定义一样的mapping:

# 先建立两个索引, 不带mapping
PUT /twitter-1
PUT /twitter-2

# 给这两个索引设置一样的mapping
PUT /twitter-1,twitter-2/_mapping
{
  "properties": {
    "user_name": {
      "type": "text"
    }
  }
}

同时给多个索引设置mapping时, 可以使用通配符, 且遵循 多个索引名称规则(multiple index names)

2. 给已存在的object字段增加新的属性

我们可以使用"put mapping api"给已有的object类型的字段增加新的属性。

我们先新建一个索引,同时指定一个object类型的字段name, 它内部有一个text类型的字段first

DELETE /my_index
PUT /my_index
{
  "mappings":{
    "properties":{
      "name":{
        "properties": {
          "first":{
            "type": "text"
          }
        }
      }
    }
  }
}

查看mapping, 这时name只有一个字段:

现在我们给这个object类型的字段name添加一个内部的text类型的字段last:

PUT /my_index/_mapping
{
  "properties":{
    "name":{
      "properties":{
        "last":{
          "type": "text"
        }
      }
    }
  }
}

再次查看mapping定义, 会发现name多了一个字段last:

3. 给一个已有的字段增加 multi-fields

multi-fields 可以让你以不同的方式去索引一个字段,从而达到不同的搜索目的。

比如, 建立一个索引, 字段city初始时是一个text类型, 支持全文搜索。

DELETE /my_index
# 建立索引
PUT /my_index
{
  "mappings":{
    "properties":{
      "city":{
        "type": "text"
      }
    }
  }
}

但是在进行 排序 或 聚合 时需要用到keyword类型以提供更高的查询效率。现在我们来给city字段添加一个keyword类型的multi-filed字段raw, 这样就可以提高该字段的排序(sorting)效率。

PUT /my_index/_mapping
{
  "properties":{
    "city":{
      "type":"text",
      "fields":{
        "raw":{
          "type":"keyword"
        }
      }
    }
  }
}

4. 更改已有字段支持的mapping参数

每个mapping参数的文档里有说明是否可以使用 put mapping api 对现有字段进行更新。例如,您可以使用 put mapping api 来更新ignore_above参数。

例如, 我们创建一个索引, 含有一个keyword类型的字段user_id, 且这个字段有一个值为20的参数ignore_above:

DELETE /my_index
PUT /my_index
{
  "mappings":{
    "properties":{
      "user_id":{
        "type": "keyword",
        "ignore_above": 20
      }
    }
  }
}
P

现在我们要用api把这个ignore_above参数的值修改为100:

PUT /my_index/_mapping
{
  "properties":{
    "user_id":{
      "type": "keyword",
      "ignore_above": 100
    }
  }
}

5. 修改已有字段的mapping

不能直接修改mapping或已有字段的类型,否则会导致已经索引的数据失效。

如果需要更改字段的mapping, 请使用正确的mapping新建一个索引,然后reindex数据到新的索引。

如果尝试通过api变更字段的类型, ES会抛出错误.

栗子: 创建一个索引users, 包含一个long类型的user_id字段, 然后写入2个文档:

PUT /users
{
  "mappings":{
    "properties":{
      "user_id":{
        "type": "long"
      }
    }
  }
}
# 插入2个文档
POST /users/_doc/12345
{
  "user_id": 12345
}
POST /users/_doc/12346
{
  "user_id": 12346
}

如果我们直接修改字段的定义会怎么样? ES会拒绝!

So, 还是老老实实的重建一个索引,然后用reindex来复制数据吧。

# 新建一个索引
PUT /users_new
{
  "mappings":{
    "properties":{
      "user_id":{
        "type": "keyword"
      }
    }
  }
}
# 使用reindex复制数据(这个复制可以执行多次, ES会自动判断是需要create还是update)
POST /_reindex
{
  "source":{
    "index": "users"
  },
  "dest":{
    "index": "users_new"
  }
}

数据复制结果:

{
  "took" : 65,
  "timed_out" : false,
  "total" : 2,
  "updated" : 0,
  "created" : 2,
  "deleted" : 0,
  "batches" : 1,
  "version_conflicts" : 0,
  "noops" : 0,
  "retries" : {
    "bulk" : 0,
    "search" : 0
  },
  "throttled_millis" : 0,
  "requests_per_second" : -1.0,
  "throttled_until_millis" : 0,
  "failures" : [ ]
}

这个reindex是用来同步一个索引的数据到另外一个索引, 会自动进行create/update/delete数据的操作.

6. 字段重命名( rename a field )

重命名字段会导致在旧的字段名称下已索引的数据无效,应该通过添加一个别名(alias)的方式来提供可替代的字段名。

栗子: 创建一个索引users, 包含一个字段user_id, 然后我们给这个字段加一个别名uid

# 字段重命名
DELETE /users
# 下建立索引
PUT /users
{
  "mappings":{
    "properties":{
      "user_id":{
        "type": "keyword"
      }
    }
  }
}
# 插入2个文档
POST /users/_doc/12345
{
  "user_id": 12345
}
POST /users/_doc/12346
{
  "user_id": 12346
}
# 给字段user_id加别名
PUT /users/_mapping
{
  "properties":{
    "uid":{
      "type": "alias",
      "path": "user_id"
    }
  }
}

添加别名后, 执行GET /users/_mapping 查看新的mapping:

{
  "users" : {
    "mappings" : {
      "properties" : {
        "uid" : {
          "type" : "alias",
          "path" : "user_id"
        },
        "user_id" : {
          "type" : "keyword"
        }
      }
    }
  }
}

现在我们来查询一下uid=12345的:

# 查询
GET /users/_search?filter_path=hits.hits
{
  "query": {
    "match": {
      "uid": 12345
    }
  }
}

是可以正常查询的, 结果如下:

返回的是原字段名称,那么如果返回别名呢? TODO

那么问题来了: 如何删除一个字段呢????? TODO




2. 获取/Get mapping

获取集群中索引的mapping定义官方文档

# 获取集群里所有索引的mapping
GET /_all/_mapping
GET /_mapping

# 获取指定索引的mapping, 可以指定索引名称或者别名
GET /<index_name_OR_index_alias>/_mappig

# 同时获取多个索引的maping, 多个索引之间以逗号分割
GET /index1,index2,index3/_mapping

ES 7.0.0版本开始弃用type, mapping定义中不再返回. 如果需要旧的格式, 可以使用参数 include_type_name=true

查询参数

allow_no_indices

当没有匹配的索引时,是否正常返回数据(否则抛出错误)。

如果设置为true, 则当使用通配符(*)、索引别名、_all匹配到的索引不存在(missing)或者已关闭(closed)时, 不会抛出错误。

默认false, 表示会抛出错误。

expand_wildcards

通配符查询时可以匹配的索引的条件, 多个值之间以英文逗号分割, 比如"open,hidden"。默认open。可用的值有:

  • all: 匹配所有open和closed的索引, 包括隐藏的(hidden).
  • open: 默认, 表示只匹配开放中的索引
  • closed: 只匹配关闭的(closed)的索引
  • hidden: 匹配隐藏的(hidden)的索引, 必须和open/closed联合使用. (官方文档说open和closed可以一起用, WAF??)
  • none: 不接受通配符.

ignore_unavailable

如果有索引不存在时是否忽略。

默认false,就是返回404并抛出错误信息。查询时只要有一个索引不存在,则都抛出错误。

官方文档说"If true, missing or closed indices are not included in the response." 这个与实测不同

local

是否仅从本地节点获取信息

默认false,表示从master节点获取信息。

master_timeout

连接到master节点的超时时间,默认 30s




3. 获取指定字段的mapping ( Get field mapping)

获取一个或多个字段的mapping定义。如果你不需要完整的mapping或者索引的字段太多时会很有用。

GET /_mapping/field/<field>
GET /<index>/_mapping/field/<field>

路径参数

  • field: 可选, 多个索引以英文逗号分割, 或者使用通配符表达式
  • field: 可选, 多个字段以英文逗号分割

查询参数

  • allow_no_indices

当没有匹配的索引时,是否正常返回数据(否则抛出错误)。

如果设置为true, 则当使用通配符(*)、索引别名、_all匹配到的索引不存在(missing)或者已关闭(closed)时,不会抛出错误。

默认true, 表示不会抛出错误。

expand_wildcards

通配符查询时可以匹配的索引的条件, 多个值之间以英文逗号分割, 比如"open,hidden"。默认是open。可用的值有:

  • all: 匹配所有open和closed的索引, 包括隐藏的(hidden).
  • open: 默认, 表示只匹配开放中的索引
  • closed: 只匹配关闭的(closed)的索引
  • hidden: 匹配隐藏的(hidden)的索引, 必须和open/closed联合使用. (官方文档说open和closed可以一起用, WAF??) -- none: 不接受通配符.

ignore_unavailable

如果有索引不存在时是否忽略。这个官方文档原文描述("If true, missing or closed indices are not included in the response.")的不准确

默认false,就是返回404并抛出错误信息。查询时只要有一个索引不存在,则都抛出错误。

include_defaults

返回的settings中是否包含默认设置, 默认是 false

local

是否仅从本地节点获取信息。

默认false, 表示从master节点获取信息。

栗子

我们先建立一个包含object的索引:

PUT /publications
{
  "mappings":{
    "properties":{
      "id":{"type": "text"},
      "title":{"type": "text"},
      "abstract":{"type": "text"},
      "author":{
        "properties":{
          "id":{"type": "text"},
          "name":{"type": "text"}
        }
      }
    }
  }
}

查看一个字段的定义

比如, 只查看title字段的定义:

GET /publications/_mapping/field/title

返回数据如下:

{
  "publications" : {
    "mappings" : {
      "title" : {
        "full_name" : "title",
        "mapping" : {
          "title" : {
            "type" : "text"
          }
        }
      }
    }
  }
}

查看多个字段的定义

  1. 如果要查看多个字段的mapping定义,可以用英文的逗号分割。且会忽略不存在的字段。
GET /publications/_mapping/field/author.id,abstract,name

上面的代码查询3个字段,但是字段name是不存在的,正确的应该是author.name,但是es是不会抛出错误的,仍然会返回有效的字段的信息。

执行结果:

# 忽略了不存在的字段 `name`, 只返回了 abstract 和 author.id
{
  "publications" : {
    "mappings" : {
      "abstract" : {
        "full_name" : "abstract",
        "mapping" : {
          "abstract" : {
            "type" : "text"
          }
        }
      },
      "author.id" : {
        "full_name" : "author.id",
        "mapping" : {
          "id" : {
            "type" : "text"
          }
        }
      }
    }
  }
}
  1. 可以使用通配符(*)

比如我们查询这个索引的所有以a开头的字段的定义:

GET /publications/_mapping/field/a*

返回数据:

{
  "publications" : {
    "mappings" : {
      "author.name" : {
        "full_name" : "author.name",
        "mapping" : {
          "name" : {
            "type" : "text"
          }
        }
      },
      "abstract" : {
        "full_name" : "abstract",
        "mapping" : {
          "abstract" : {
            "type" : "text"
          }
        }
      },
      "author.id" : {
        "full_name" : "author.id",
        "mapping" : {
          "id" : {
            "type" : "text"
          }
        }
      }
    }
  }
}

返回的字段的顺序并不是按索引的mapping中定义的顺序来的。通常我们获取索引的完整的mapping时,字段是按照字母升序排列的。

查询多个索引的多个字段的定义

查询请求格式GET /<index>/_mapping/field/<field>中的<index><field>支持逗号分割的多个名称,或通配符。如果要查询所有的索引, 可以用_all来表示索引名称。

# 查询多个索引的一个字段
GET /twitter,users/_mapping/field/message

# 查询所有索引的多个字段
GET /_all/_mapping/field/message,user.id

# 查询所有索引的字段中内含id字段(那就是object类型了)
GET /_all/_mapping/field/*.id

注意: 使用_all查询返回的结果和我们预想的不大一样:会返回所有的索引,但是每个索引的mapping中如果没有这个字段则显示空json。比如GET /_all/_mapping/field/message,user.id返回的部分数据如下:

{
  "users_new" : {
    "mappings" : { }
  },
  ".apm-custom-link" : {
    "mappings" : { }
  },
  "kibana_sample_data_ecommerce" : {
    "mappings" : { }
  },
  ".kibana_task_manager_1" : {
    "mappings" : { }
  },
  ".apm-agent-configuration" : {
    "mappings" : { }
  },
  "kibana_sample_data_logs" : {
    "mappings" : {
      "message" : {
        "full_name" : "message",
        "mapping" : {
          "message" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  },...
}

4. 查询类型是否存在 (Type exists)

因ES 7.0.0废弃了type, 相应的Type exists查询也废弃了

HEAD /<index>/_mapping/<type>

返回状态码:

指定的mapping类型存在返回200, 只要有一个类型不存在就返回状态404

last updated at 2021/10/22 14:40

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部