Removal of mapping types——ES官方文档学习

Removal of mapping types这部分的官方说明
我原来没系统看官方文档时候,也写过一篇类似的文章,还是从官方说明再细细的看一下

在ES6.0以及更高版本中创建的索引应该尽量只包含单个映射类型。
ES5.X具有多种映射类型的索引在6.0将继续像以前那样运行。但是多个映射类型的方式将在ES7.0中完全删除。

What are mapping types?

es从开始每个文档都会被放在独立的索引里,并且给这个文档指定一个Mapping type。而这个type就用来表示type下文档的类型。比如对于twitter索引,就可能会有user和tweet两种类型。
每个mapping type有自己的数据域,而每个文档被创建索引后也都会有_index表示索引名字,_type表示mapping type。

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

上面的查询就是在一个索引下的两个type查找

Why are mapping types being removed?

ES的开发者最初希望让用户这样理解,“索引”类似于SQL数据库中的“数据库”,type等价于table。
这被认为是一个糟糕的类比,导致了错误的假设。因为在SQL数据库中,表是相互独立(BC范式以后),一个表中的列与另一个表中具有相同名称的列没有关联,但这不是映射类型中的字段的情况,比如上面的user和tweet两个type都有user_name这个字段。
1.在ElasticSearch索引中,因为是封装的lucene,lucene解决这个问题的办法是:不同type中具有相同名称的字段在内部会是一个相同的Lucene field。换句话说,使用上面的示例,user中的user_name字段存储在与tweet类型中的user_name字段是被储存成完全相同的字段中,并且两个user_name字段在两种类型中必须具有相同的定义,比如想要对这个字段进行统一操作,这个字段的type必须相同。所以假如在同一索引中删除user被存成long的“ID”字段,由于tweet存成了“keyword”,那这就有可能会导致失败。
2.此外,在同一索引中存储很少或没有共同字段的不同实体会导致数据稀疏,并干扰Lucene有效压缩文档的能力。
由于这些原因,所以从ES删除多个映射类型的概念。

Alternatives to mapping types

Index per document type

第一种替换方式就是一种类型一个索引,比如上面的twitter_user和twitter_tweet两个索引,每一个单独创建,索引之间肯定没有冲突。
这种方法有两个好处:
1.由于Lucene中使用的压缩技术数据更可能是密集的;
2.用于全文搜索的评分可能更准确,因为同一索引中的所有文档都是一种类型。
此外,每个索引的大小可以根据它所包含的文档数量进行适当调整:比如您可以为user索引使用较少数量的shards(分片,主要用来解决数据量过大无法单机存储),为tweet使用较多的shards。

Custom type field

第二种方法是自定义type的字段,就是你在一个索引里面直接写明那个type,每次添加doc的时候也要确定是哪一个type。还是那上面的twitter举例子:
原来的时候是这样的:

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": "shay@kimchy.com"
}

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"
    }
  }
}

现在你可以自定义一个type字段,用来表明是user还是tweet,但是所有字段都在里面:

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": "shay@kimchy.com"
}

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" 
        }
      }
    }
  }
}

这时候,user_name在不同type的查询可以利用bool查询来实现,_type变成的默认的_doc

Parent/Child without mapping types

第三种方式有很多时候多映射类型是父子类型,针对这种特殊情况,原来就有的父子特型还会继续保留。只是关联手段需要用到join datatype,join的具体使用以后学到它再说
原来是这样做的:
还是多个type,只是子type中有个属性_parent的type字段写成parent的type名称,不过6.0已经不能这样了,还是贴一下以便比较:

PUT index_test
{
  "mappings": {
    "type_info": {
      "properties": {
        "userId": {
          "type": "integer"
        },
        "mobile": {
          "type": "keyword"
        },
        "nick": {
          "type": "keyword"
        },
        "vipType": {
          "type": "integer"
        },
        "vipPoints": {
          "type": "integer"
        },
        "regTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        }
      }
    },
    "type_order": {
      "_parent": {
        "type": "type_info"
      },
      "properties": {
        "amount": {
          "type": "scaled_float",
          "scaling_factor": 100
        },
        "payMethod": {
          "type": "integer"
        },
        "status": {
          "type": "integer"
        },
        "productCount": {
          "type": "integer"
        }
      }
    }
  }
}


PUT index_test/type_info/1000
{
    "userId": 1000,
    "mobile": "13301020202",
    "nick": "梅西",
    "vipType": 1,
    "vipPoints": 1200,
    "regTime": "2018-06-18 12:00:31"
}

PUT index_test/type_order/100?parent=1000
{
    "userId": 1000,
    "amount": 300,
    "payMethod": 2,
    "status": 3,
    "productCount": 2
}

现在只能有一个type的情况下,应该像下面那样:

PUT index_test
{
  "mappings": {
    "_doc": {
      "properties": {
        "userId": {
          "type": "integer"
        },
        "mobile": {
          "type": "keyword"
        },
        "nick": {
          "type": "keyword"
        },
        "vipType": {
          "type": "integer"
        },
        "vipPoints": {
          "type": "integer"
        },
        "regTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        },
        "amount": {
          "type": "scaled_float",
          "scaling_factor": 100
        },
        "payMethod": {
          "type": "integer"
        },
        "status": {
          "type": "integer"
        },
        "productCount": {
          "type": "integer"
        },
        "type_order": {
          "type": "join",
          "relations": {
            "people": "order"
          }
        }
      }
    }
  }
}

PUT index_test/_doc/1000
{
  "userId": 1000,
  "mobile": "13301020202",
  "nick": "梅西",
  "vipType": 1,
  "vipPoints": 1200,
  "regTime": "2018-06-18 12:00:31",
  "type_order":"people"
}
PUT index_test/_doc/1001?routing=1&refresh 
{
  "userId": 1000,
  "amount": 300,
  "payMethod": 2,
  "status": 3,
  "productCount": 2,
  "type_order":{
    "name": "order", 
    "parent": "1000" 
  }
}

官方文档下面讲的就是删除多type的计划,以及提供reindex的api,用来将多type迁移到单个type,这些我暂时也用不到,由困惑的时候看一下就好了。

“Removal of mapping types——ES官方文档学习”的一个回复

发表评论

电子邮件地址不会被公开。