为了学习目的,我试图在Redis中编写一个简单的结构化文档存储库。在我的示例应用程序中,我将数百万个文档编入索引,这些文档看上去有点像以下内容使用Redis进行复合查询
<book id="1234">
<title>Quick Brown Fox</title>
<year>1999</year>
<isbn>309815</isbn>
<author>Fred</author>
</book>
我正在写一个小的查询语言,让我说YEAR = 1999 AND TITLE="Quick Brown Fox"
(再次,只是为了我的学习,我不在乎,我重新发明轮子!),应返回的ID的匹配文件(在这种情况下为1234
)。表达式的AND
和OR
可以任意嵌套。
对于我生成密钥如下
BOOK_TITLE.QUICK_BROWN_FOX = 1234
BOOK_YEAR.1999 = 1234
我使用
SADD形式
KEYNAME.VALUE = { REFS }
到扑通在一系列套这些文件
每个文档。
当我进行查询时,我将表达式解析为AST。一个简单的表达式,例如YEAR=1999
直接映射到一个SMEMBERS命令,该命令让我返回一组匹配文档。但是,我不确定如何最有效地执行AND和OR部分。
给定的查询,如:
(TITLE=Dental Surgery OR TITLE=DIY Appendectomy)
AND
(YEAR = 1999 AND AUTHOR = FOO)
我目前做如下要求的Redis来回答这些疑问。
-- Stage one generates the intermediate results and returns RANDOM_GENERATED_KEY3
SUNIONSTORE RANDOMLY_GENERATED_KEY1 BOOK_TITLE.DENTAL_SURGERY BOOK_TITLE.DIY_APPENDECTOMY
SINTERSTORE RANDOMLY_GENERATED_KEY2 BOOK_YEAR.1999 BOOK_YEAR.1998
SINTERSTORE RANDOMLY_GENERATED_KEY3 RANDOMLY_GENERATED_KEY1 RANDOMLY_GENERATED_KEY2
-- Retrieving the top level results just requires the last key generated
SMEMBERS RANDOMLY_GENERATED_KEY3
当我遇到一个AND
我用SINTERSTORE基于两个子键(同样地,对于OR
我用SUNIONSTORE)。我随机生成一个密钥来存储结果(并设置一个短的TTL,所以我不会用Cruft填充Redis)。在这一系列命令结束时,返回值是我可以用来检索SMEMBERS的结果的一个键。我使用商店功能的原因是我不想将所有匹配的文档引用传输回服务器,因此我使用临时密钥将结果存储在Redis实例上,然后仅将匹配结果返回到结束。
我的问题很简单,这是使用Redis作为文档存储的最佳方式吗?
这种方法有多快? – mixdev 2011-05-19 12:34:55
我遵循这种方法,并且发现它非常快(与Redis相关的大多数事情一样)。你可以做的很酷的事情之一是缓存中间键以获得缓存的查询片段(如下面的Tom所建议的)。为了避免在病态情况下存储中间密钥(例如,在整个文档集中带有AND和OR的空集),我还对和和进行了一些优化。 – 2011-05-19 18:20:54