Elasticsearch - 如何存储数据,嵌套还是数组?

时间:2017-09-07 05:07:13

标签: elasticsearch

请帮帮我。 如何为这些数据制定最佳文档方案? 有关每个城市的产品数量的数据:

  1. product1, [city = city1, available = 0], [city = city2, available = 2], [city = city3, available = 1], ... ...
  2. product100, [city = city1, available = 1], [city = city2, available = 1], [city = city3, available = 1], ...
  3. 如果产品可以是1000个,城市可以是100个并且城市可用的搜索工作,那么如何为每个产品保存这些数据?

4 个答案:

答案 0 :(得分:1)

我会将它们存储如下:

{
  "product" : "product1",
  "city-avail" : [
      {
        "city" : "city1",
        "available" : 0
      },
      {
        "city" : "city2",
        "available" : 1
      }
    ]
}
{
  "product" : "product2",
  "city-avail" : [
      {
        "city" : "city3",
        "available" : 1
      },
      {
        "city" : "city2",
        "available" : 0
      }
    ]
}

答案 1 :(得分:1)

对于复杂数据(如键值对),我会使用嵌套字段类型。对于简单数据,如带数字或字符串的数组,我使用数组字段类型。

因此,在您的情况下,如果您要关联"对象"与城市和可用项目我会使用嵌套字段。然后,您可以通过嵌套字段进行搜索和聚合。

答案 2 :(得分:1)

这完全取决于您想要查询数据的方式。 当我们将数据存储为对象数组时,我们失去了相关性 因此,如果您将数据存储为 -

prodId : id,
availability: [
    { city: city1, available: true},
    { city: city2, available: false}
   ]

ES会在索引时在内部展平对象,并将其编入索引 -

availability.city= [city1,city2]
availability.available= [true,false]

现在,如果您想检查city2中可用的产品,则此文档将符合资格。

如果要保持关联,则应使用嵌套对象。嵌套对象被视为单独的文档,由ES内部管理。连接由ES在内部执行,因此您不必担心它,并且可以对其进行聚合。在不利方面,嵌套对象会降低系统速度,因为需要更多的分片级别通信。

答案 3 :(得分:0)

您的数据集(1000个产品/ 100个城市)非常小。如果您不希望它扩展到更大,您可以使用嵌套数据结构(这是最明显的解决方案)。你的映射看起来像这样:

{
  "product": {
    "properties": {
      "product": {"type": "keyword"},
      "cities": {
        "type": "nested",
        "properties": {
          "name": {"type": "keyword"},
          "available": {"type": "integer"}
        }
      }
    }
  }
}

然后你会索引看起来像这样的文件:

{
  "product": "product1",
  "cities": [
    {
      "name": "city1",
      "available": 0
    },
    {
      "name": "city2",
      "available": 1
    }
  ]
}

但是,嵌套查询和聚合是昂贵/缓慢的,因此如果您希望数据集大幅增长,您可能需要考虑denormalizing your data。在您的情况下,我可以看到一些可能的想法,这取决于您想要如何查询数据。

简单展平(每个城市/产品组合一个doc):

Doc 1:
{
  "product": "product1",
  "city": "city1",
  "available": 0
}
Doc 2:
{
  "product": "product1",
  "city": "city2",
  "available": 1
}

这方面的缺点是您无法轻松按产品进行搜索(因为产品是重复的)。您可以通过在需要以这种方式进行查询时保留单独的产品索引来解决这个问题。

如果您从未期望获得超过100(或1000)的城市,则每个城市可以有一个字段,如下所示:

{
  "product": "product1",
  "city1": 0,
  "city2": 1,
  ...
}

请注意,如果您这样做,您实际上并不需要拥有每个源文档中的所有城市 - 缺少密钥就可以了。 "下方"这是因为您需要提前知道您感兴趣的城市的名称(以便查询),以便查询。可能这对您来说不是正确的解决方案,但在某些用例中它很有用。

如果您的可用数字总是很低,并且您希望始终如此(例如,如果您从未期望有超过10个可用),您可以执行以下操作:

{
  "product": "product1",
  "available": {
    "0": ["city1", "city2"],
    "1": ["city2"],
    "2": [],
    ...
  }
}

因此,如果您想查看city1是否包含该产品(无论它们是否可用),您可以查询available.0,如果您想查看它是否至少有1个可用,那么您可以查询available.1等。如果您想查看product1至少有1个可用的城市,您可以在available.1上执行术语聚合。如果你使用这种数据结构,你可能想要添加另一个字段,它将包含每个城市的确切数字(不是嵌套的,因此对于查询不是很有用,但是为了方便你检索数据)。