指数和类型之间的差异

很容易看到 types 像 SQL 数据库中的表,其中 index 是 SQL 数据库。然而,这不是接近 types 的好方法。

关于类型

实际上,类型实际上只是 Elasticsearch 添加到每个文档的元数据字段:_type。上面的例子创建了两种类型:my_typemy_other_type。这意味着与类型相关联的每个文档都有一个自动定义的额外字段,如 "_type": "my_type"; 这是使用文档编制索引,从而使其成为可搜索或可过滤的字段,但它不会影响原始文档本身,因此你的应用程序无需担心它。

所有类型都存在于同一索引中,因此位于索引的相同集合分片中。即使在磁盘级别,它们也存在于相同的文件中。创建第二种类型提供的唯一分离是合乎逻辑的。每种类型,无论它是否唯一,都需要存在于映射中,并且所有这些映射必须存在于集群状态中。这会占用内存,如果每种类型都是动态更新的,它会随着映射的变化而降低性能。

因此,最佳实践是仅定义单个类型,除非你确实需要其他类型。通常会看到需要多种类型的场景。例如,假设你有汽车索引。你可以使用多种类型对其进行细分:

  • 宝马
  • 烦扰
  • 本田
  • 马自达
  • 奔驰
  • 日产
  • rangerover
  • 丰田

这样,你可以搜索所有汽车或按制造商按需限制。这两次搜索之间的区别很简单:

GET /cars/_search

GET /cars/bmw/_search

对 Elasticsearch 的新用户来说,不明显的是第二种形式是第一种形式的特化。它实际上被重写为:

GET /cars/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term" : {
            "_type": "bmw"
          }
        }
      ]
    }
  }
}

它只是过滤掉任何未使用 _type 字段索引的文档,其值为 bmw。由于每个文档都以其类型为 _type 字段编制索引,因此这是一个非常简单的过滤器。如果在任一示例中都提供了实际搜索,则过滤器将根据需要添加到完整搜索中。

因此,如果类型相同,则提供单一类型(例如,在此示例中为 manufacturer)并且有效地忽略它会好得多。然后,在每个文档中,明确提供一个名为 make 的字段或你喜欢的任何名称,并在你想要限制它时手动过滤它。这将减少映射到 1/n 的大小,其中 n 是单独类型的数量。它确实为每个文档添加了另一个字段,这是为了简化映射。

在 Elasticsearch 1.x 和 2.x 中,这样的字段应该定义为

PUT /cars
{
  "manufacturer": { <1>
    "properties": {
      "make": { <2>
        "type": "string",
        "index": "not_analyzed"
      }
    }
  }
}
  1. 这个名字是任意的。
  2. 该名称是任意的*,如果你也想要它,*它可以匹配类型名称。

在 Elasticsearch 5.x 中,上面的代码仍然可以使用(它已被弃用),但更好的方法是使用:

PUT /cars
{
  "manufacturer": { <1>
    "properties": {
      "make": { <2>
        "type": "keyword"
      }
    }
  }
}
  1. 这个名字是任意的。
  2. 该名称是任意的*,如果你也想要它,*它可以匹配类型名称。

应该在索引中谨慎使用类型,因为它会使索引映射膨胀,通常没有太大的好处。你必须至少有一个,但没有任何东西说你必须有一个以上。

常见问题

  • 如果我有两个(或更多)类型大多相同但每个类型有一些唯一字段会怎么样?

在索引级别,存在正在与被稀疏地使用的几个领域中使用的一种类型之间没有差别多种类型的,与几个不共享(意味着其它类型甚至从未共享一束非稀疏字段之间采用现场(一个或多个))。

换句话说: *无论类型如何,*稀疏使用的字段在索引上都是稀疏的。稀疏性不会因为它是以单独的类型定义而对索引有益 - 或者真正受到伤害。

你应该只组合这些类型并添加单独的类型字段。

  • 为什么单独的类型需要以完全相同的方式定义字段?

因为每个字段实际上只在 Lucene 级别定义一次,无论有多少类型。类型存在的事实是 Elasticsearch 的一个特征,它只是一个逻辑分离。

  • 我可以定义具有不同定义的相同字段的单独类型吗?

不。如果你设法在 ES 2.x 或更高版本中找到这样做的方法,那么你应该打开一个错误报告 。如前一个问题所述,Lucene 将它们视为单个字段,因此无法使其正常工作。

ES 1.x 将此作为隐式要求,允许用户创建条件,其中索引中的一个分片映射实际上与同一索引中的另一个分片不同。这实际上是一种竞争条件,可能会导致意想不到的问题。

规则的例外情况

  • 父/子文档需要在同一索引中使用单独的类型。
    • 父母住在一种类型。
    • 孩子生活在一个单独的类型中(但每个孩子与其父母住在同一个碎片中)。
  • 非常小众的使用案例,其中创建大量的指数是不可取的,稀疏领域的影响优于替代方案。
    • 例如,Elasticsearch 监控插件 Marvel(1.x 和 2.x)或 X-Pack 监控(5.x +)监控 Elasticsearch 本身的集群,节点,索引,特定索引(索引级别)的变化,甚至是碎片。它可以每天创建 5 个以上的索引来隔离那些具有唯一映射的文档,或者它可能违反最佳实践以通过共享索引来减少集群负载(注意:已定义映射的数量实际上是相同的,但是创建的索引的数量从 n 减少到 1)。
    • 这是一种高级方案,但你必须考虑跨类型的共享字段定义!