映射

一、概述

(1)映射
映射是定义文档如何被存储和索引的,包括含有哪些字段,字段的类型,字符串类型的字段应当作为全文本还是关键字,日期字段的格式等等。

(2)映射类型
每个索引都有唯一一个映射类型(Elasticsearch计划去除映射类型,详情看第二节),映射类型决定了文档是如何被索引的。一个索引类型包括了:
元字段:用于定义文档的元数据关联如何处理。元字段包括文档的_index字段、_type字段、_id字段和_source字段。
字段或属性:每个映射类型包含文档相关的一系列字段或属性。

(3)字段数据类型
每个字段拥有一个数据类型。可以是简单数据类型,比如文本型(text)、关键字型(keyword)、日期型(date)、长整型(long)、双精度浮点型(double)、布尔型(boolean)或者IP;也可以是支持JSON的层次性的类型,比如对象(object)、嵌套(nested);或者其它特殊类型,比如地理点(geo_point)、地理形状(geo_shape)、完成型(completion)。

为了不同的目的,以不同的方式对相同的字段进行索引通常是有用的。 例如,字符串字段可以被索引为全文搜索的文本字段,以及用于排序或聚合的关键字字段。

这是多字段的目的。 大多数数据类型通过fields参数支持多字段。

(4)防止映射爆炸的设置
在索引中定义太多的字段是可能导致映射爆炸,这会导致内存错误和难以恢复的情况。 这个问题可能比预期的更普遍。 例如,考虑插入每个新文档引入新字段的情况。 这在动态映射中很常见。 每次文档包含新字段时,这些都将导致索引的映射增长。 少量的数据这不需要担心,但随着映射的增长,这可能成为一个问题。 以下设置允许您限制手动或动态创建的字段映射的数量,以防止不良文档导致映射爆炸:

index.mapping.total_fields.limit
索引的最大字段数,默认为1000。

index.mapping.depth.limit
字段的最大深度,该深度用于表示内部对象的数量。例如,如果所有字段都是在根级别对象定义的,则深度为1。如果存在一个对象映射,则深度为2,以此类推。默认值是20。

index.mapping.nested_fields.limit
索引中嵌套字段的最大数目,默认为50。索引一个含有100个嵌套字段的文档实际上索引了101文档, 因为每个嵌套文档都被索引为单独的隐藏文档。

(5)动态映射
字段和映射类型在使用之前不需要定义。由于动态映射,只需索引一个文档,新的字段名称可以自动加入。可以将新字段添加到顶层映射类型以及内部对象和嵌套字段。

可以配置新字段的动态映射规则。

(6)显示映射
如果你非常了解自己的数据,而无需elasticsearch去猜测,你可以显示指定映射。可以在创建索引时,创建字段映射;也可以使用PUT映射API向已存在的映射添加字段。

(7)更新已存在的字段映射
除了文档的位置,已存在字段映射不能够更新。改变映射意味着已索引文档无效。相反,你应该用正确的映射创建新的索引,并重新索引你的数据到新的索引上。

二、去除映射类型

注意:在Elasticsearch 6.0.0或更高版本中创建的索引可能只包含一个映射类型。在5.x中创建的 使用多种映射类型的索引将继续像以前一样在Elasticsearch 6.x中运行。 映射类型将在Elasticsearch 7.0.0中完全删除。

什么是映射类型?

自Elasticsearch首次发布以来,每个文档都被存储在一个索引中,并被分配了一个映射类型。 映射类型用于表示被索引的文档或实体的类型,例如,twitter索引可能有一个user类型和tweet类型。

每个映射类型可以有自己的字段,所以user类型可能有一个full_name字段,一个user_name字段和一个email字段,而tweet类型可以有一个content字段,一个tweeted_at字段,和一个与用户类型一样的user_name字段。

每个文档都有一个包含类型名称的_type元字段,通过在URL中指定类型名称,可以限制搜索一种或多种类型:

GET twitter/user,tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}

_type字段与文档的_id结合生成_uid字段,因此具有相同_id的不同类型的文档可以存在于同一个索引中。

也使用映射类型来建立文档之间的父子关系。

为什么要去除映射类型?

最初,我们谈到了索引类似于SQL数据库中的“数据库”,类型与表相当。

这是一个不好的类比,导致错误的假设。 在一个SQL数据库中,表是相互独立的。 一个表中的列与另一个表中相同名称的列没有关系。 映射类型的字段不是这种情况。

在Elasticsearch索引中,在不同映射类型中具有相同名称的字段在内部由相同的Lucene字段支持。 换句话说,使用上面的示例,用户类型中的user_name字段存储在与tweet类型中的user_name字段完全相同的字段中,并且这两个user_name字段在两种类型中都必须具有相同的映射(定义)。

最重要的是,在同一索引中,存储有少量公共字段(甚至没有公共字段)的不同实体,会导致稀疏数据并影响Lucene高效压缩文档的能力。

由于这些原因,Elasticsearch将去除映射类型的概念。

替代映射类型

  • 一个索引一个文档类型

第一个选择是每个文档类型都有一个索引。 不将tweet和user存储在同一个twitter索引中,而是将tweet存储在tweet索引中,并将user存储在user索引中。索引是完全相互独立的,所以索引之间不存在字段类型的冲突。

这种方法有两个好处:
(1)数据更可能是密集的,因此受益于Lucene中使用的压缩技术。
(2)在全文搜索中用于计分的索引词统计更可能是准确的,因为同一索引中的所有文档都代表单个实体。

每个索引的大小可以根据其包含的文档数量适当调整:user可以使用较小数量的主分片,并tweet可以使用较大数量的主分片。

  • 自定义类型字段

当然,在一个集群中可以存在的主分片数是有限制的。所以,你可能不想为只有几千个文档的集合浪费整个分片。在这种情况,你可以实现自己的自定义类型字段,它将以类似于旧的_type的方式工作。

以上面的user/tweet为例。 最初,工作流将看起来像这样:

PUT twitter
{
  "mappings": {
    "user": {
      "properties": {
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" }
      }
    },
    "tweet": {
      "properties": {
        "content": { "type": "text" },
        "user_name": { "type": "keyword" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/user/kimchy
{
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "[email protected]"
}

PUT twitter/tweet/1
{
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}

您可以通过添加自定义类型字段来实现相同的功能,如下所示:

PUT twitter
{
  "mappings": {
    "doc": {
      "properties": {
        "type": { "type": "keyword" }, 
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" },
        "content": { "type": "text" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/doc/user-kimchy
{
  "type": "user", 
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "[email protected]"
}

PUT twitter/doc/tweet-1
{
  "type": "tweet", 
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "user_name": "kimchy"
        }
      },
      "filter": {
        "match": {
          "type": "tweet"
        }
      }
    }
  }
}
  • 不使用映射类型定义父子关系

以前,通过使一个映射类型为父,一个或多个映射类型为子来表示父子关系。没有映射类型,我们不能再使用这个语法。父子特性将继续像以前一样其作用,除了表达文档间父子关系的方法更改为使用新的join字段。

迁移多类型索引到单类型

Reindex API可用于将多类型索引转换为单类型索引。 以下示例可用于Elasticsearch 5.6或Elasticsearch 6.x。在6.x中,不需要指定index.mapping.single_type,因为这是默认值。

  • 一个索引一个文档类型

第一个示例将我们的Twitter索引分成一个tweets索引和一个user索引:

PUT users
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "user": {
      "properties": {
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT tweets
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "tweet": {
      "properties": {
        "content": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "user"
  },
  "dest": {
    "index": "users"
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "tweet"
  },
  "dest": {
    "index": "tweets"
  }
}
  • 自定义类型字段

下面的示例添加一个自定义类型字段, 并将其设置为原始 _type 的值。它还会将类型添加到 _id 中, 防止不同类型的文档有ID冲突:

PUT new_twitter
{
  "mappings": {
    "doc": {
      "properties": {
        "type": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        },
        "content": {
          "type": "text"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}


POST _reindex
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter"
  },
  "script": {
    "source": """
      ctx._source.type = ctx._type;
      ctx._id = ctx._type + '-' + ctx._id;
      ctx._type = 'doc';
    """
  }
}

你可能感兴趣的:(映射)