从这个角度来看/需求,ES有一个巨大的局限性:
- 尽管具有动态映射,但ES不是无模式的,而是模式密集型的。如果此更改与现有文档冲突,则无法更改映射(实际上,如果任何文档具有新映射影响的非空字段,这将导致异常)
- ES 中的文档是不可变的:一旦您索引了一个文档,您只能检索/删除。围绕这一点的语法糖是部分更新,这使得线程安全的删除+索引(具有相同的id)在ES端
在你的问题中,这意味着什么?基本上,您不能拥有适用于ES的经典迁移工具。以下是可以简化ES工作的方法:
所以,一点点经验。对我来说,目前合理的流程是这样的:
- 所有数据结构在代码中描述为模型。这个模型实际上也提供了ORM抽象。
- 索引/映射创建调用是简单模型的方法。
- 每个索引都有别名(即 ),它指向实际索引(即 )。
news
news_index_{revision}_{date_created}
每次部署代码时,您
- 尝试放置模型(类型)映射。如果它没有错误,这意味着你已经
- 放置相同的映射
- 放置映射是旧字段的纯超集(仅提供新字段,旧字段保持不变)
- 没有文档在受新映射影响的字段中具有值
所有这些实际上意味着你很高兴使用你拥有的映射/数据,只是像往常一样使用数据。
- 如果 ES 提供了有关新映射的异常,则
- 使用新映射创建新索引/类型(命名为 like
name_{revision}_{date}
- 将别名重定向到新索引
- 启动发出快速重新索引
的批量
请求的迁移代码 在此重新编制索引期间,您可以通过别名正常安全地为新文档编制索引。缺点是历史数据在重新编制索引期间部分可用。
这是经过生产测试的解决方案。关于这种方法的警告:
- 如果您的读取请求需要一致的历史数据,则无法执行此操作
- 您需要对整个索引重新编制索引。如果每个索引有1种类型(可行的解决方案),那么它很好。但有时您需要多类型索引
- 数据网络往返。有时可能是疼痛
总结一下:
- 尝试在模型中具有良好的抽象性,这总是有帮助的
- 尝试使历史数据/字段保持陈旧状态。只需在构建代码时牢记这个想法,这比一开始听起来更容易
- 我强烈建议避免依赖利用 ES 实验工具的迁移工具。这些可以随时更改,就像工具一样。
river-*