在我的多租户应用(基于每个帐户的用户数的帐户)中,如何更改用户文档时如何更新特定帐户的索引。
我为每个帐户都有一个单独的索引,其中指定了每个模型的映射(用户和评论 - 只是一个示例实际应用程序有很多模型)。在这种情况下,如果对用户模型或注释模型进行了任何更改,则必须更新为相关帐户创建的索引。这可能吗?如果是,请告诉我。
我想这就是我在我的情况下指定映射的方式。如果我错了,请纠正我。
帐户模型:
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
使用帐户索引的映射正确创建索引。但是,当映射中指定的任何模型发生更改时,我没有看到可以更新索引的方法。
每当添加新用户或更新用户时,必须更新为相应帐户创建的索引。
答案 0 :(得分:3)
此问题是从Github问题Multiple model single index approach交叉发布的。在这里改写答案。
假设我们有一个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”订阅的帐户可以在两周后搜索,但是具有“基本”订阅的帐户只能在本周搜索。
另请注意,articles_current别名指向当前周的ehm(我在2012-07-12周四写这篇文章)。下周的索引就在那里,铺设和等待 - 当时机到来时,后台工作(cron,Resque worker,自定义脚本......)将更新别名。在Tire集成测试套件中的“滑动窗口”场景中有一个带有别名的漂亮示例。
我们现在不要看看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与articles_currentindex别名对话,后者会定期更新到当前一周的后台进程。通过这种方式,我们在应用程序的不同组件中分离了用于设置索引名称的所有逻辑,因此我们不需要访问索引代理中的Article或Account类(它在单独的服务器上运行),或任何应用程序的组件。无论哪个组件是索引,都是针对articles_current别名的索引;无论哪个组件正在搜索,搜索任何别名或索引对特定组件都有意义。
答案 1 :(得分:0)
你可能想要使用像rubberband https://github.com/grantr/rubberband这样的另一个gem来设置你想要的索引,事先,也许你在after_create回调中创建帐户
然后在映射您的用户和评论模型时,您可以使用Tire执行以下操作:
tire.mapping :_routing => { :required => true, :path => :account_id } do
index_name 'account_name_here'
...
...
end
棘手的部分是将account_id或name添加到index_name字符串/参数中,可能很容易或者很难,还没有尝试过动态分配index_name
希望这有帮助!