【问题标题】:Elastic Search reindex API - how to preserve destination index mapping?弹性搜索重新索引 API - 如何保留目标索引映射?
【发布时间】:2021-10-20 14:13:00
【问题描述】:

my-index-0 成为一个别名为 my-index 的 ES 索引。

它有以下映射:

{
    "my-index-0": {
        "aliases": {
            "my-index": {}
        },
        "mappings": {
            "doc": {
                "properties": {
                    "foo": {
                        "properties": {
                            "fizz": {
                                "type": "keyword"
                            },
                            "baz": {
                                "type": "keyword"
                            }
                        }
                    }
                }
            }
        }
    }
}

假设我想从foo 中删除baz 字段。我正在使用以下步骤:

  1. 使用PUT /my-index-1 创建一个新的索引my-index-1 并更新映射(删除foo.baz
{
    "mappings": {
        "doc": {
            "properties": {
                "foo": {
                    "properties": {
                        "fizz": {
                            "type": "keyword"
                        },
                    }
                }
            }
        }
    }
}
  1. 使用POST /_reindex 将数据从my-index-0 重新索引到my-index-1
{
  "source": {
    "index": "my-index-0"
  },
  "dest": {
    "index": "my-index-1"
  }
}
  1. 使用POST /_aliasesmy-index 别名移动到my-index-1 索引
{
    "actions": [
        {"remove": {"index": "my-index-0", "alias": "my-index"}},
        {"add": {"index": "my-index-1", "alias": "my-index"}},
    ]
}

预期结果

新索引中的数据没有foo.baz 属性。

实际结果

在创建my-index-1 时,其映射不包含foo.baz 字段,但是在重新索引后,my-index-1 的映射将更改为旧索引的映射。

注意:_source 可用于简单的字段移除

如果要删除一个字段,例如,从下面的映射中删除bar

{
    "mappings": {
        "foo": {
            "type": "text"
        },
        "bar": {
            "type": "text"
        }
    }
}

在重新索引 API 的请求中提供不带 bar 字段的 _source 参数就足够了:

{
  "source": {
    "index": "my-index-0",
    "_source": ["foo"]
  },
  "dest": {
    "index": "my-index-1"
  }
}

如何用嵌套结构实现相同的效果?

【问题讨论】:

    标签: elasticsearch reindex


    【解决方案1】:

    当您使用reindex 时,ES 会尝试将所有数据从源索引复制到目标索引。如果您想让您的索引不被修改,您需要将此行添加到您的映射中:

    "dynamic" : "strict"
    

    现在如果你想reindex 数据你会得到一个错误"strict_dynamic_mapping_exception" 因为"mapping set to strict, dynamic introduction of [baz] within [foo] is not allowed"。所以你需要像这样删除reindex 中的这个字段:

    POST _reindex
    {
      "source": {
        "index": "my-index-0"
      },
      "dest": {
        "index": "my-index-1"
      },
      "script": {
        "source": "ctx._source.remove(\"foo.baz\")"
      }
    }
    

    注意:添加"dynamic" : "strict" 是可选的,可以防止您的索引被修改。如果您只编辑您的 reindex 查询,它将对您有用。

    【讨论】:

    • 这是一个很好的评论!我曾想过使用“脚本”,但在一般情况下 (see my answer) 似乎更难处理。问题是,我希望能够处理任意索引,而无需为每种情况编写自定义 reindex 查询。
    【解决方案2】:

    我想我找到了我正在寻找的通用解决方案。

    _source 属性中,可以明确指定每个嵌套字段,因此,示例中场景的_source 值应该是["foo.fiz"] - 请注意缺少"foo.bar"应该' t 被复制。

    {
      "source": {
        "index": "my-index-0",
        "_source": ["foo.fiz"]
      },
      "dest": {
        "index": "my-index-1"
      }
    }
    

    本质上,为一般情况生成"_source" 属性的问题可以简化为查找新旧映射的所有属性路径集的交集。

    Python 解决方案

    下面的函数递归遍历属性并产生所有属性​​路径。

    def get_property_path(properties: dict[str, Any], name: str = "") -> Iterator[str]:
        for property_name, property_value in properties.items():
            new_name = f"{name}.{property_name}" if name else property_name
            if nested_properties := property_value.get("properties"):
                yield from get_property_path(nested_properties, new_name)
            else:
                yield new_name
    

    例如

    >>> properties = {
        "a": {
            "properties": {
                "b": {
                    "properties": {
                        "c": {"type": "text"},
                    },
                },`
            },
        },
        "e": {
            "properties": {
                "f": {"type": "text"},
            },
        },
    }
    >>> list(get_property_path(properties))
    >>> ['a.b.c', 'e.f']
    

    它可以稍后用于计算应该复制的字段集(旧映射和新映射中的字段):

    _source = list(
        set(get_property_path(old_mapping["properties"]))
        & set(get_property_path(new_mapping["properties"]))
    )
    

    我不会接受我的回答,因为可能有一个基于 ES API 的更简单的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-01
      相关资源
      最近更新 更多