【问题标题】:Single index multi type - elasticsearch indexing via tire单索引多类型 - 通过轮胎进行弹性搜索索引
【发布时间】:2013-05-23 00:31:30
【问题描述】:

在我的多租户应用程序(基于每个帐户的用户数的帐户)中,当用户文档发生更改时,我将如何更新特定帐户的索引。

我对每个帐户都有一个单独的索引,其中指定了每个模型(用户和 cmets - 只是一个示例实际应用程序有许多模型)的映射。在这种情况下,如果对用户模型或评论模型进行了任何更改,则必须更新为相关帐户创建的索引。这可能吗?如果是,请告诉我。

我想这是我指定映射的方式。如果我错了,请纠正我。

帐户模型:

include Tire::Model::Search

Tire.index('account_1') do
  create(
    :mappings => {
      :user => {
        :properties => {
          :name => { :type => :string, :boost => 10 },
          :company_name => { :type => :string, :boost => 5 }
        }
      },
      :comments => {
        :properties => {
          :description => { :type => :string, :boost => 5 }
        }
      }
    }
  )
end

使用帐户索引的两个映射正确创建索引。但是,当映射中指定的任何模型发生更改时,我看不到可以更新索引的方法。

每当添加新用户或更新用户时,必须更新为相应帐户创建的索引。

【问题讨论】:

  • 这个问题在 Github 和 Stackoverflow 上已经讨论了一遍又一遍...
  • 是的。确实如此。但是,我仍在寻找解决方案。如果我要更新同一模型中的数据,@karmi 建议的对 update_index 方法的调用似乎有效。即,为用户模型创建索引并使用 after_save 钩子调用 update_index。然后索引正在更新。但是,我想为具有多类型映射(用户和 cmets)的每个帐户创建一个索引,并希望在更新用户或评论模型时更新帐户索引。

标签: ruby-on-rails elasticsearch ruby-on-rails-2 tire


【解决方案1】:

这个问题是从 Github 问题 Multiple model single index approach 交叉发布的。在这里交叉发布答案。


假设我们有一个 Account 类并且我们处理文章实体。

在这种情况下,我们的 Account 类将具有以下内容:

class Account
  #...

  # Set index name based on account ID
  #
  def articles
      Article.index_name "articles-#{self.id}"
      Article
  end
end

因此,每当我们需要访问特定帐户的文章时,无论是搜索还是索引,我们都可以这样做:

@account = Account.find( remember_token_or_something_like_that )

# Instead of `Article.search(...)`:
@account.articles.search { query { string 'something interesting' } }

# Instead of `Article.create(...)`:
@account.articles.create id: 'abc123', title: 'Another interesting article!', ...

在某些情况下,为每个用户/帐户设置一个单独的索引是完美的——但在您拥有数万或数十万个(或更多)索引的情况下绝对不是很好。在这种情况下,拥有索引别名并正确设置过滤器和路由会表现得更好。我们不会根据租户身份,而是根据时间对数据进行切片。

让我们看看第二种情况,从一个高度简化的 curl http://localhost:9200/_aliases?pretty 输出开始:

{
  "articles_2012-07-02" : {
    "aliases" : {
      "articles_plan_pro" : {
      }
    }
  },
  "articles_2012-07-09" : {
    "aliases" : {
      "articles_current" : {
      },
      "articles_shared" : {
      },
      "articles_plan_basic" : {
      },
      "articles_plan_pro" : {
      }
    }
  },
  "articles_2012-07-16" : {
    "aliases" : {
    }
  }
}

您可以看到我们有三个索引,每周一个。您可以看到有两个相似的别名:articles_plan_pro 和articles_plan_basic - 显然,订阅“pro”的帐户可以搜索两周前,但订阅“basic”的帐户只能搜索本周。

还要注意,articles_current 别名指向,嗯,本周(我在 2012 年 7 月 12 日星期四写这篇文章)。下周的索引就在那里,等待中——到时候,后台作业(cron、Resque worker、自定义脚本……)将更新别名。在轮胎集成测试套件的“滑动窗口”场景中有一个漂亮的别名示例。

我们现在先不看articles_shared别名,看看我们可以用这个设置玩什么花样:

class Account
  # ...

  # Set index name based on account subscription
  #
  def articles
    if plan_code = self.subscription && self.subscription.plan_code
      Article.index_name "articles_plan_#{plan_code}"
    else
      Article.index_name "articles_shared"
    end
    return Article
  end
end

再一次,我们为 Article 类设置了一个 index_name,它保存了我们的文档。当当前账号有有效订阅时,我们从订阅中取出plan_code,直接在相关索引中搜索该账号:“basic”或“pro”。

如果帐户没有订阅——他可能是“访问者”类型——我们会将搜索定向到articles_shared 别名。使用界面和以前一样简单,例如。在 ArticlesController 中:

@account  = Account.find( remember_token_or_something_like_that )
@articles = @account.articles.search { query { ... } }
# ...

在这种情况下,我们没有使用 Article 类作为索引的网关;我们有一个单独的索引组件,一个 Sinatra 应用程序,作为 elasticsearch Bulk API 的轻代理,提供 HTTP 身份验证、文档验证(强制执行规则,如所需属性或作为 UTC 传递的日期),并使用裸 Tire::Index#import和 Tire::Index#store API。

这些 API 与 article_currentindex 别名对话,该别名通过所述后台进程定期更新到当前周。通过这种方式,我们解耦了在应用程序的单独组件中设置索引名称的所有逻辑,因此我们不需要访问索引代理中的 Article 或 Account 类(它运行在单独的服务器上),或任何应用程序的组成部分。无论哪个组件正在索引,都针对articles_current 别名进行索引;无论哪个组件正在搜索,搜索对特定组件有意义的任何别名或索引。

【讨论】:

    【解决方案2】:

    您可能想使用另一个 gem,例如橡皮筋 https://github.com/grantr/rubberband 以您想要的方式设置索引,事先,也许在创建帐户时,您在 after_create 回调中执行此操作

    然后在映射您的 User 和 Comment 模型时,您可以使用 Tire 执行以下操作:

    tire.mapping :_routing => { :required => true, :path => :account_id } do
      index_name 'account_name_here'
      ...
      ...
    end
    

    棘手的部分是将 account_id 或 name 放入 index_name 字符串/参数中,可能容易或困难,尚未尝试动态分配 index_name

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 1970-01-01
      • 2023-01-31
      • 1970-01-01
      • 2012-03-13
      • 2013-07-27
      相关资源
      最近更新 更多