2013-11-15 2 views
5

Я использую Rethinkdb 1.10.1 с официальным драйвером python. У меня есть таблица меченых вещей, которые связаны с одним пользователем:Как создать составной мультииндекс в rethinkdb?

{ 
    "id": "PK", 
    "user_id": "USER_PK", 
    "tags": ["list", "of", "strings"], 
    // Other fields... 
} 

Я хочу запросить по user_id и 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 и тегов. Такой индекс позволит мне задать вопрос:

res = r.table('things').get_all(['USER_PK', 'TAG'], index='user_tags').run(conn) 

В состав документации по составным мультииндексам ничего нет. Тем не менее, I попытался использовать пользовательскую функцию индекса, сочетающую требования к составным индексам и мультииндексам, возвращая список из ["USER_PK", "tag"] пар.

Моя первая попытка была в питоне:

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

Это делает заслонку драйвер питона с MemoryError пытается разобрать функции индекса (я думаю списочные не очень поддерживается драйвером).

Итак, я обратился к моему (правда, ржавый) яваскрипт и придумал это:

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

Между прочим. В последней версии драйвера Rethink python при запуске я получаю сообщение об ошибке, объясняющее, что я делаю неправильно. Возможно ли, что у вас установлена ​​более старая версия драйвера? –

+0

У меня есть версия 1.10.0-0, которую я установил на прошлой неделе. По-видимому, в PyPI нет новой версии. Вы имеете в виду версию разработки? – tawmas

ответ

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 не всегда связан с фактическим документом из базы данных, он привязан к специальной переменной питона, который представляет собой документ.Я бы на самом деле попробуйте запустить следующий раз, чтобы продемонстрировать это:

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.

+1

Спасибо большое! Я полностью игнорировал функцию карты в документах. – tawmas