如何在rethinkdb中创建复合多索引?

taw*_*mas 5 rethinkdb rethinkdb-python

我正在使用Rethinkdb 1.10.1与官方python驱动程序.我有一个与一个用户关联的标记事物表:

{
    "id": "PK",
    "user_id": "USER_PK",
    "tags": ["list", "of", "strings"],
    // Other fields...
}
Run Code Online (Sandbox Code Playgroud)

我想查询user_id和tag(比如,用标签"tag"查找用户"tawmas"的所有内容).从Rethinkdb 1.10开始,我可以像这样创建一个多索引:

r.table('things').index_create('tags', multi=True).run(conn)
Run Code Online (Sandbox Code Playgroud)

我的查询将是:

res = (r.table('things')
       .get_all('TAG', index='tags')
       .filter(r.row['user_id'] == 'USER_PK').run(conn))
Run Code Online (Sandbox Code Playgroud)

但是,此查询仍需要扫描具有给定标记的所有文档,因此我想基于user_id和tags字段创建复合索引.这样的索引允许我查询:

res = r.table('things').get_all(['USER_PK', 'TAG'], index='user_tags').run(conn)
Run Code Online (Sandbox Code Playgroud)

文档中没有关于复合多索引的内容.但是,我尝试使用自定义索引函数,通过返回对列表来["USER_PK", "tag"]组合复合索引和多索引的要求.

我的第一次尝试是在python中:

r.table('things').index_create(
    'user_tags',
    lambda each: [[each['user_id'], tag] for tag in each['tags']],
    multi=True).run(conn)
Run Code Online (Sandbox Code Playgroud)

这使得python驱动程序扼杀了MemoryError试图解析索引函数(我猜驱动程序不支持列表推导).

所以,我转向我的(诚然,生锈的)javascript并想出了这个:

r.table('things').index_create(
    'user_tags',
    r.js(
        """(function (each) {
            var result = [];
            var user_id = each["user_id"];
            var tags = each["tags"];
            for (var i = 0; i < tags.length; i++) {
                result.push([user_id, tags[i]]);
            }
            return result;
        })
        """),
    multi=True).run(conn)
Run Code Online (Sandbox Code Playgroud)

这被服务器拒绝,但有一个奇怪的例外: rethinkdb.errors.RqlRuntimeError: Could not prove function deterministic. Index functions must be deterministic.

那么,定义复合多指数的正确方法是什么?或者这是目前不支持的东西?

Joe*_*ner 7

简短回答:

列表推导在ReQL函数中不起作用.你需要map像这样使用:

r.table('things').index_create(
    'user_tags',
    lambda each: each["tags"].map(lambda tag: [each['user_id'], tag]),
    multi=True).run(conn)
Run Code Online (Sandbox Code Playgroud)

答案很长

这实际上是RethinkDB驱动程序工作方式的一个微妙方面.所以这不起作用的原因是你的python代码实际上并没有看到每个文档的真实副本.所以在表达式中:

lambda each: [[each['user_id'], tag] for tag in each['tags']]
Run Code Online (Sandbox Code Playgroud)

each它不会绑定到数据库中的实际文档,而是绑定到表示文档的特殊python变量.我实际上尝试运行以下内容来演示它:

q = r.table('things').index_create(
       'user_tags',
       lambda each: print(each)) #only works in python 3
Run Code Online (Sandbox Code Playgroud)

它会打印出如下内容:

<RqlQuery instance: var_1 >
Run Code Online (Sandbox Code Playgroud)

驱动程序只知道这是函数的一个变量,特别是它不知道是否each["tags"]是一个数组或什么(它实际上只是另一个非常相似的抽象对象).所以python不知道如何迭代该字段.基本上javascript中存在完全相同的问题.