RethinkDB: создать индекс для поля во вложенном массиве (запуск в сценарий больших данных)

Вот пример документа:

{
    "id": 12345,
    "links": [
        {
            url: "http://something.com",
            created: 1234567890987
        },
        {
            url: "http://somethingelse.com",
            created: 1234567891548
        },
        {
            url: "http://somethingweird.com",
            created: 1234567898555
        }
    ]
}

Поле created - это просто временная метка unix. Я хочу иметь возможность выполнять индексированные запросы в поле created, содержащемся в каждом элементе массива links. Я понятия не имею, как это сделать (или если это возможно). Например, этот запрос больше не может быть выполнен, так как в таблице очень много документов (около 7 миллионов):

r.db('test').table('very_large_table')
  .filter(function(row) {
    return row('links').filter(function(link) {
        return link('created').ge(1425293715379) 
    }).isEmpty().not()
  })
  .count()

ИЗМЕНИТЬ. Поскольку набор данных очень велик, я отказался от запросов в реальном времени для стратегии агрегирования. Теперь вместо того, чтобы пытаться запрашивать эти данные по запросу, у нас есть очереди сообщений и задания агрегирования данных, которые сжимают эти данные, чтобы они уже обрабатывались и запрашивались очень быстро. Еще раз спасибо всем за помощь!


person haggy    schedule 03.03.2015    source источник


Ответы (2)


Вы можете создать мультииндекс для created полей следующим образом:

r.db('test').table('very_large_table')
 .indexCreate('links_created', r.row('links')('created'), {multi:true})

И используйте индекс так:

r.db('test').table('very_large_table')
 .between(1425293715379, null, {index:'links_created'})

См. Документацию здесь: http://rethinkdb.com/docs/secondary-indexes/python/ < / а>

person AtnNn    schedule 03.03.2015
comment
Спасибо @AtnNn! Я видел свойство multi в документации, но не мог понять, каково его практическое использование. Теперь я знаю! - person haggy; 04.03.2015
comment
Итак, я создал индексы (потребовалось некоторое время). В таблице сейчас около 8 миллионов строк. Я попробовал этот запрос (метка времени - 1 марта): r.db('dev').table('really_large_table') .between(1425186000000, null, {index: 'multi_links_created'}) .count() И он все еще не завершен :( Прошло около 3 минут ... есть мысли? - person haggy; 05.03.2015
comment
Если индекс не полностью помещается в кеш, возможно, он загружает что-то с диска. Вы используете SSD или ротационный накопитель? Можете ли вы проверить журналы сервера (в проводнике данных) на наличие такого сообщения, как Автоматическое использование размера кэша X МБ, и проверить, имеет ли X разумный размер? Вы можете изменить настройку, записав в r.db ('rethinkdb'). Table ('server_config'). Update ({cache_size_mb: NEW_VALUE}). - person Daniel Mewes; 05.03.2015
comment
И еще одно: запрос r.db('dev').table('really_large_table') .between(1425186000000, null, index: 'multi_links_created'}) .count() фактически подсчитывает количество ссылок, которые были созданы после указанной временной метки, а не количество документов. Если есть один документ, который имеет несколько ссылок, созданных после отметки времени, этот документ будет подсчитан запросом несколько раз. Вы можете изменить запрос на ...between(...)('id').distinct().count(), но это не сработает, если у вас более 100 000 новых ссылок. Дайте мне знать, если вам нужна эта семантика для дополнительных ссылок. - person Daniel Mewes; 05.03.2015
comment
@DanielMewes Документы могут иметь несколько элементов в массиве links. Сейчас в таблице около 8 миллионов, но это количество документов, а не ссылок. Здесь как минимум столько же ссылок, сколько документов. Что касается вашего вопроса о SSD, да, мы работаем с SSD-дисками. Я считаю, что кеш составляет около 5 ГБ (на сервере с 64 ГБ оперативной памяти). Просто чтобы вы знали, что count() запрос так и не был завершен. Дала поработать часа 3 ... - person haggy; 05.03.2015

Просто чтобы прояснить вопрос: это проблема производительности. Запрос работает, но из-за количества документов в вашей базе данных ему трудно выполнить этот запрос.

Я бы сказал, что у вас есть два варианта: попытаться оптимизировать ваш запрос или изменить схему ваших документов.

http://rethinkdb.com/docs/secondary-indexes/javascript/

1. Оптимизация запроса

Кажется, что ваш запрос работает, но он мог бы быть более эффективным. В вашем примере вы просматриваете все ссылки в каждом отдельном документе и запускаете .ge для каждой из них. Возможно, вы могли бы получить .max или .min всех ссылок, а затем сравнить их с помощью .ge. Я почти уверен, что это будет быстрее, но не уверен, что это будет достаточно быстро.

r.db('test').table('rethink_question_timestamp_index')
  .hasFields('links')
  .map(function (row){ return row('links').max('created')('created') })
  .filter(r.row.ge(1425293715379))
  .count()

2. Изменение схемы

Если вместо ссылок внутри документа вы создали еще одну link таблицу, а затем вставили в нее ссылки, используя связь «один ко многим» с документами в very_large_table, тогда вы могли бы создать индекс в поле created, который ускорит запросы по ссылкам, а затем использовать _ 9_, чтобы объединить ссылки и их родительские документы.

С веб-сайта RethinkDB:

«Создайте новый вторичный индекс для таблицы. Вторичные индексы улучшают скорость многих запросов чтения за счет небольшой стоимости увеличения дискового пространства и снижения производительности записи».


ОБНОВЛЕНИЕ

@AtnNn прав. Создание вторичного индекса для вложенного свойства - лучший способ!

http://rethinkdb.com/docs/secondary-indexes/javascript/

person Jorge Silva    schedule 03.03.2015
comment
Спасибо Хорхе. Ребята, вы очень помогаете! Отмечен ответ AtnNn. - person haggy; 04.03.2015