首页 > 解决方案 > 在 Elixir Phoenix 中保存/更新后在 Elasticsearch 中创建文档

问题描述

我试图找出在 SQL 数据库中创建新行之后将文档插入/更新到 elasticsearch(或任何 nosql 数据库)的最佳流程,以及将逻辑放在 Elixir Phoenix 中的位置。

想象一下我的 SQL 表是postshas_many comments,并且我的 elasticsearch 结构有一个posts索引,其中comments是一个嵌套文档,所以我可以同时搜索/检索帖子和评论内容。这意味着如果用户创建或更新他们的评论消息,post弹性搜索中的相关文档应该更新。

最好的方法是什么?

标签: elasticsearchnosqlelixirphoenix-framework

解决方案


确切的实现可能取决于几件事:操作有多快,用户是否需要知道结果?

如果两个操作都相当快(即用户可以等待),那么您可以使用一个简单的with语句来确保两个操作都成功完成,例如

with {:ok, _result1} <- update_postgres(data),
  {:ok, _result2} <- update_elasticsearch(data) do
   {:ok, "Everything updated!"}
end

如果您需要围绕将 2 个操作“绑定”在一起的更多形式,那么Ecto 事务就可以完成这项工作。文档通常假设操作都是数据库操作或者它们使用相同的操作Repo,但是您可以在事务中执行任意任务,例如更新 Elasticache:

  def two_things(data) do
    My.Repo.transaction fn ->
      with {:ok, _result1} <- update_postgres(data),
           {:ok, _result2} <- update_elasticache(data)
      do
        {:ok, "Everything updated!"}
      else
        {:error, e} -> 
           My.Repo.rollback(e)
           {:error, "Something failed!"}
    
      end
    end
  end

只有当您需要在失败时执行回滚时,使用事务才真正有意义。

此处的另一个选项假定操作可能足够慢,以至于您不希望让用户等待它们完成。通常,至关重要的“主要”操作是更新数据库。有时其他相关的更新(例如在缓存层中)最好留给异步的副作用。例如:

result = update_postgres(data)
Task.async(fn -> update_elasticache(data) end)
result

或者只有在数据库操作成功时才​​触发副作用:

case update_postgres(data) do
  {:ok, result} -> 
    Task.async(fn -> update_elasticache(data) end)
    {:ok, result}
  {:error, error} -> {:error, error}
end

或者更简洁的语法:

with {:ok, result} <- update_postgres(data) do
  Task.async(fn -> update_elasticache(data) end)
    {:ok, result}
end

有许多语法/助手可以完成此操作,但其想法是任何辅助操作都是非阻塞的,并且可以在将结果返回给用户后完成。


推荐阅读