我正在使用Rethinkdb 1.10.1与官方python驱动程序。我有一个与一个用户关联的标记事物表:
{
"id": "PK",
"user_id": "USER_PK",
"tags": ["list", "of", "strings"],
// Other fields...
}
我想通过user_id
和tag
进行查询(比如,用标签“tag”查找用户“tawmas”的所有内容)。从Rethinkdb 1.10开始,我可以创建一个这样的多索引:
r.table('things').index_create('tags', multi=True).run(conn)
我的查询将是:
res = (r.table('things')
.get_all('TAG', index='tags')
.filter(r.row['user_id'] == 'USER_PK').run(conn))
但是,此查询仍需要扫描具有给定标记的所有文档,因此我想基于user_id和tags字段创建复合索引。这样的索引允许我查询:
res = r.table('things').get_all(['USER_PK', 'TAG'], index='user_tags').run(conn)
文档中没有关于复合多索引的内容。但是,我
试图使用自定义索引函数结合复合的要求
通过返回["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)
这使得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)
服务器拒绝了这一点,但有一个奇怪的例外:rethinkdb.errors.RqlRuntimeError: Could not prove function deterministic. Index functions must be deterministic.
那么,定义复合多指数的正确方法是什么?或者它是什么 目前不支持哪个?
答案 0 :(得分: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)
长答案
这实际上是RethinkDB驱动程序工作方式的一个微妙方面。所以这不起作用的原因是你的python代码实际上并没有看到每个文档的真实副本。所以在表达式中:
lambda each: [[each['user_id'], tag] for tag in each['tags']]
each
从未绑定到数据库中的实际文档,它绑定到表示文档的特殊python变量。我实际上尝试运行以下内容来演示它:
q = r.table('things').index_create(
'user_tags',
lambda each: print(each)) #only works in python 3
它会打印出类似的内容:
<RqlQuery instance: var_1 >
驱动程序只知道这是函数的一个变量,特别是它不知道each["tags"]
是一个数组还是什么(它实际上只是另一个非常相似的抽象对象)。所以python不知道如何迭代该字段。基本上javascript中存在完全相同的问题。