1

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

通过 Tire gem 使用 Elasticsearch。

Rails 2.3 应用程序 - 应用更改以根据loe/tire 的提交启用对 Rails 2.3 的支持

账户模式:

  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

正如您在上面看到的,这里有两个模型用户和评论。使用多个模型解决单个索引是否正确?

在这种情况下,当单独更改用户文档或评论文档时如何更新索引?

4

2 回答 2

0

通常,当您为模型编制索引时,最好将自身属性与其关联一起编制索引。因此,在这种情况下,如果您想要索引用户及其评论,您应该在用户模型中拥有索引并索引其关联引用的评论,以便轮胎回调应用于用户模型以重新索引用户对象(如果模型中有任何属性)被改变。这仅适用于您拥有索引的模型。

如果你想索引关联,你需要有钩子,在保存/销毁用户/评论模型之后索引帐户对象。或者您也可以使用 :touch => true 选项在用户/评论更改时触摸帐户模型。

示例:如果您想要索引用户和评论,

  include Tire::Model::Search
  include Tire::Model::Callbacks

     mapping do
        indexes :id,                  :type => 'integer', :index    => :not_analyzed
        indexes :about_me,            :type => 'string',  :index    => :snowball
        indexes :name,                :type => 'string',  :index    => :whitespace

        indexes :comments do
          indexes :content,                  :type => 'string', :analyzer => 'snowball'
        end
    end

所以这里的索引是在用户模型上,而 user.comments 是一个关联。希望这个例子能解释

于 2012-11-14T07:00:34.390 回答
0

轮胎老板Karmi发布的问题的答案如下:

假设我们有一个 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 别名进行索引;无论哪个组件正在搜索,搜索对特定组件有意义的任何别名或索引。

于 2013-01-03T11:41:24.433 回答