使用Redis进行复合查询

出于学习目的,我正在尝试在Redis中编写一个简单的结构化文档存储.在我的示例应用程序中,我正在索引数百万个看起来有点像下面的文档.

<book id="1234">
    <title>Quick Brown Fox</title>
    <year>1999</year>
    <isbn>309815</isbn>
    <author>Fred</author>
</book>

我正在写一个小的查询语言,允许我说YEAR = 1999和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,所以我不会用redft填充Redis).在这一系列命令结束时,返回值是我可以用SMEMBERS检索结果的一个键.我使用存储函数的原因是我不想将所有匹配的文档引用传回服务器,所以我使用临时密钥将结果存储在Redis实例上,然后只返回匹配的结果.

我的问题很简单,这是将Redis用作文档存储的最佳方式吗?

最佳答案 我正在使用类似的排序集方法来实现全文索引.整体方法很好,尽管你可以做一些相当简单的改进.

>您可以使用查询(或其简短形式)作为密钥,而不是使用随机生成的密钥.这使您可以重用已经计算过的集合,如果您对通常以类似方式组合的两个大集合进行查询,则可以显着提高性能.
>将标题作为完整字符串处理将导致大量单个成员集.如果您确实需要,可能最好对标题中的单个单词进行索引并过滤最终结果以进行完全匹配.

点赞