我有User模型对象,其中包含很少的字段(属性,如果您愿意)。说“名字”,“姓氏”,“城市”和“出生年份”。每个用户也获得“唯一ID”。
我希望能够通过它们进行搜索。我该怎么做呢?如何做到这一点?
我的理解(几乎适用于任何键值存储 - 首先是键,然后是值)
u:123456789 = serialized_json_object
(“u”作为用户密钥的简单前缀,123456789是“唯一ID”)。
现在,我想我希望能够通过名字和姓氏进行搜索,我可以保存:
f:史蒂夫=你:384734807,你:2398248764,你:23276263 f:Alex = u:12324355,u:121324334
所以键是“f” - 这是firstnames的前缀,而“Steve”是实际的名字。 对于“你:史蒂夫”,我们将所有用户ID保存为“Steve's”。
这使得每次搜索都非常容易。通过少数字段(属性)查询 - 比如firstname(即“Steve”)和姓氏(即“l:Anything”)仍然很容易 - 首先从“f:Steve”获取用户ID列表,然后从“l”列出:任何“,找到交叉用户ID,在这里你去。
问题(并且有很多):
保存,更新,删除用户是一件痛苦的事。它必须是原子和一致的操作。此外,如果我们的价值规模限制在某个值 - 那么我们就处于(潜在)麻烦之中。真的不是这里的答案。只压缩用户ID列表?不过不太酷。
我们想要添加新字段以进行搜索。最终。用“城市”说。我们当然可以采用相同的方式“c:洛杉矶”= ...,“c:芝加哥”= ......,但如果我们从一开始就没有预见到所有这些“搜索选择”,那么我们就会有能够创建一些夜间工作或所有现有用户记录,并为他们更新那些“c:CITY”...相当大的工作!
锁定问题。用户“u:123”更新他的名字“Alex”,用户“u:456”更新他的名字“Alex”。他们都必须用他们的身份更新“f:Alex”。这意味着要么我们遇到覆盖问题,要么一次更新会等待另一次更新(如果有很多则进行成像?!)。
这样做的最佳方法是什么?请记住,我想在很多领域进行搜索?
P.S。请问,问题是关于HBase / Cassandra / NoSQL / Key-Value存储。请 - 请不要使用MySQL和“读取”SELECT;并担心“以后”缩放问题。我之所以如此问我的问题是有道理的。 :-)
答案 0 :(得分:4)
能够直接查询属性是远离SQL时丢失的功能之一,因此您需要一种方法来维护自己的索引以便查找记录。
如果您的数据存储区没有内置索引或原子列表操作,则需要处理您提到的锁定问题。但是,索引不一定需要是同步的 - 维护一个更新记录的队列以重新编制索引,并且您有一个3的解决方案,可以重复使用以解决2。
如果特定值的索引列表变得太大,系统无法在单个列表中处理,则可以使用列表列表替换用户列表。但是,如果你有那么多具有相同值的记录,那么它可能不是一个特别有用的搜索条件。
在某些情况下有用的另一个选项是使用单独的系统进行索引 - 例如,您可以设置lucene来索引主数据存储区中的记录。
答案 1 :(得分:1)
我想我会将其作为MapReduce作业实现,该作业将按计划运行。 每个搜索词都是一个行键,可以查找UID。
Rowkey: UID1
个人资料:firstName:乔
个人资料:lastName:Doe
个人资料:nick:DoeMaster
Rowkey: uid2
个人资料:firstName:Jane
个人资料:lastName:Doe
个人资料:nick:SuperBabe
MapReduse索引所有可搜索的属性,并将搜索词添加为行键
罗基:简
查询:uid:uid2
Rowkey:Doe
查找:uid:uid2,uid1
Rowkey:DoeMaster
查询:uid:uid1
...等
现在,如果您需要在用户更改时动态更新索引列表,您可以将更改直接写入索引库,方法是从索引中删除uid值并添加到另一个行键。如果同时发生这种情况,可以实施临时锁定。
对于被删除的用户,可以使用告知用户状态的其他属性将其从搜索中过滤掉。
添加额外的搜索词并不是很难,因为它只是关于你要索引的名称:value。您还可以通过向行键/关键字添加type属性来过滤搜索。即波士顿 - 查询:类型:城市。
我们的想法是在hbase中维护您自己的基于行键的搜索索引。