Эффективный поиск по убыванию времени создания в Raik

Я учусь использовать Raik, движок NoSQL. Учитывая, что у меня есть пользовательская «хронология» с сообщениями, и это сообщение может варьироваться от миллионов до миллиардов, как я могу взять последние N сообщений из ведра raik? Я имею в виду, последний созданный.

Я читал, что при использовании вторичного индекса Raik будет возвращать сообщения, упорядоченные по ключу. Поэтому я решил использовать UUID1 для почтовых ключей и иметь вторичный индекс для автора сообщения, чтобы я мог получать все сообщения от этого автора, используя его ключ.

Однако сообщения сортируются по ВОЗРАСЧЕНИЮ! Я также хочу использовать параметр max_results в качестве ПРЕДЕЛА SQL.

Однако этот запрос возвращает ПЕРВЫЕ N сообщений этого пользователя, а не последние. Учитывая, что я уже видел несколько сообщений StackOverflow и что предлагаемое решение MapReduce неэффективно для больших сегментов, как бы вы моделировали данные или написали запрос?

Спасибо


person Francesco Boffa    schedule 09.10.2013    source источник


Ответы (2)


При переходе из среды SQL корзину легко рассматривать как таблицу и хранить в ней небольшие отдельные записи, часто полагаясь на вторичные индексы для получения данных. Поскольку Riak — это хранилище ключей и значений, использующее последовательное хеширование, это, однако, часто не самый эффективный или масштабируемый подход.

Поиск на основе ключа в Riak позволяет напрямую идентифицировать разделы, содержащие данные, и координирующий узел может напрямую запрашивать эти разделы. При запросе дополнительного индекса Riak не знает, в каких разделах данные который может соответствовать индексу, будет находиться. Поэтому потребуется отправить запрос в большое количество разделов, чтобы убедиться, что все соответствующие объекты могут быть найдены. Это известно как «запрос покрытия» и означает, что при условии, что n_val, равное 3, используется для корзины, необходимо запросить как минимум 1/3 всех разделов. Как правило, это приводит к более высокой нагрузке на кластер и не масштабируется так же хорошо, как прямой поиск ключей. Задержки также имеют тенденцию быть выше.

Поэтому при использовании Riak часто рекомендуется структурировать данные так, чтобы можно было как можно чаще использовать прямой поиск по ключу, например. посредством денормализации.

Если ваши сообщения/сообщения можно как-то сгруппировать, например. пользователем или разговором, может иметь смысл хранить их в одном объекте, представляющем эту группу, а не в виде отдельных объектов.

Если предположить, что ваши сообщения могут состоять из текста или изображений и связаны с веткой беседы, вы можете создать объект, представляющий ветку беседы. Это будет содержать информацию о разговоре, а также список сообщений. Этот список сообщений может, например. содержат идентификатор постера, отметку времени и ключ записи, содержащей пост. Если пост представляет собой достаточно короткое текстовое сообщение, он может даже содержать весь пост, уменьшая количество записей, которые необходимо будет извлечь.

По мере поступления сообщений в этот разговор запись обновляется, а список сообщений увеличивается. Может быть целесообразно установить для allow_mult значение true, чтобы включить братьев и сестер, так как это позволит вам обрабатывать параллельные записи. Этот подход позволяет вам всегда получать разговор, а также последние сообщения с помощью единого прямого поиска по ключу.

Riak работает лучше всего, когда размер объектов не превышает пару МБ. Поэтому в какой-то момент вам нужно будет переместить самые старые сообщения в отдельный объект, чтобы контролировать размер. Если вы храните список этих связанных объектов в основном объекте беседы, возможно, вместе с некоторой информацией об интервале времени, который они охватывают, вы также можете легко получить к ним доступ с помощью прямого поиска по ключу, если вам нужно прокрутить старые сообщения.

Поскольку наиболее распространенный запрос обычно относится к самым последним записям, его всегда можно выполнить через основной объект диалога.

Я также хотел бы отметить, что у нас есть очень активный список рассылки, где такие вопросы обсуждаются довольно часто.

person Christian Dahlqvist    schedule 10.10.2013
comment
Большое спасибо за обширный ответ. Вы только что запретили мне использовать вторичные индексы для любого отношения has_many/one. В другом потоке на SO было предложено использовать подход связанного списка, используя заголовок «Ссылка», чтобы имитировать предыдущую/следующую цепочку, и иметь «первую» ссылку на пользователя или разговор. Это потребует N поисков для N сообщений. Когда N мало (‹ 10), приемлемы ли тайминги для веб-приложения? Единственная альтернатива — ваша группировка, но allow_mult меня пугает. Мне нужно объединить двух братьев и сестер. Изолирование сообщений предотвратило бы двойную запись (99,999%). - person Francesco Boffa; 10.10.2013
comment
Вторичные индексы имеют множество применений, в том числе используются для указания родительского объекта в отношениях «один ко многим». Важно спроектировать модель таким образом, чтобы этот метод доступа не был основным, особенно если у вас есть приложение с высоким соотношением операций чтения и записи. Я бы также рекомендовал не пытаться поддерживать связанный список, используя ссылки или ссылки в объекте, поскольку это легко может сломаться, если у вас есть одновременные обновления/вставки и/или сетевые разделы. - person Christian Dahlqvist; 10.10.2013
comment
Включение братьев и сестер не должно быть пугающим. В этом случае вы можете рассматривать список сообщений как набор. Если вы сталкиваетесь с братьями и сестрами, вы выполняете объединение наборов между доступными наборами, а затем сортируете их по отметке времени, прежде чем записывать их обратно в Riak. Однако, если у вас очень высокая частота публикации, что приводит к частым обновлениям, может быть сложно правильно разрешить братьев и сестер. В этом случае часто рекомендуется пытаться направлять все операции записи/обновления через один (или небольшое количество) потоков, чтобы снизить риск возникновения одноуровневых потоков. - person Christian Dahlqvist; 10.10.2013
comment
Ok. Понятно, почему связанные списки плохи. Единственная проблема с методом группировки заключается в том, что у меня не будет единого объекта, представляющего сообщение, и его можно будет прочитать только тогда, когда беседа и подмножество сообщений также будут прочитаны. Я считаю, что именно здесь происходит денормализация. Мне нужно ведро беседы (с группами отсортированных сообщений) и ведро сообщений (с отдельными сообщениями). Спасибо за уделенное время :) - person Francesco Boffa; 10.10.2013
comment
Идеальное решение вашей проблемы будет зависеть от ваших шаблонов доступа. Если у вас высокий коэффициент записи/чтения, вторичные индексы могут быть правильным выбором, но если ваше приложение интенсивно читается, часто имеет смысл использовать собственные индексы, как я описал, поскольку это обеспечивает более эффективное извлечение. Полезный пост в блоге, объясняющий это, можно найти здесь: basho.com/index- для развлечения и прибыли - person Christian Dahlqvist; 10.10.2013

Я знаю, что, вероятно, уже слишком поздно, чтобы помочь вам, но я нашел этот пост, задаваясь вопросом о том же. Обходной путь, который я придумал и успешно использовал, заключается в создании двух вторичных индексов, один с реальной меткой времени, а другой (MAX_DATE - метка времени). Выполнение поиска по первому запросу дает восходящие результаты, а выполнение поиска по второму запросу — нисходящие результаты (после того, как вы выполните математические операции, чтобы превратить его обратно в реальную дату). Максимальное значение даты можно найти в спецификации Javascript, например, в MDN, то есть 8640000000000000. Я не могу сказать, насколько он эффективен при очень большой нагрузке, но могу сказать вам, что для моих целей он был невероятно быстрым, и я очень доволен. Я просто пришел сюда в надежде найти менее хакерский способ сделать это.

person rmeador    schedule 12.12.2014