Поиски (и общие запросы) с помощью HBase и/или Cassandra (лучшие практики?)

У меня есть объект модели User с несколькими полями (свойствами, если хотите). Произнесите «имя», «фамилию», «город» и «год рождения». Каждый пользователь также получает «уникальный идентификатор».

Я хочу иметь возможность искать по ним. Как мне это сделать правильно? Как это сделать вообще?

Насколько я понимаю (будет работать практически для любого хранилища ключей-значений - сначала идет ключ, затем значение)

u: 123456789 = объект_сериализованного_json

(«u» — простой префикс для ключей пользователя, 123456789 — «уникальный идентификатор»).

Теперь, думая, что я хочу иметь возможность искать по имени и фамилии, я могу сохранить в:

f:Стив = u:384734807,u:2398248764,u:23276263 f:Alex = u:12324355,u:121324334

таким образом, ключ "f" - это префикс для имен, а "Стив" - это настоящее имя. Для "u:Steve" мы сохраняем как значение все идентификаторы пользователей, которые являются "Steve's".

Это делает каждый поиск очень-очень легким. Запрос по нескольким полям (свойствам) -- скажем, по имени (т. е. "Стив") и фамилии (т. е. "l:Anything") по-прежнему прост - сначала получите список идентификаторов пользователей из "f:Steve", затем список из "l :Anything", найдите пересекающиеся идентификаторы пользователей и вперед.

Проблемы (а их немало):

  1. Сохранение, обновление, удаление пользователя - это боль. Это должна быть атомарная и последовательная операция. Кроме того, если у нас есть размер значения, ограниченный некоторым значением, то у нас (потенциальные) проблемы. И действительно не ответ здесь. Заархивировать только список идентификаторов пользователей? Впрочем, не слишком круто.

  2. По какому идентификатору мы хотим добавить новое поле для поиска. В конце концов. Скажем "город". Мы конечно можем сделать так же "c:Los Angeles" = ..., "c:Chicago" = ..., но если мы не предусмотрели все эти "варианты поиска" с самого начала, то у нас будет чтобы иметь возможность создать какое-то ночное задание или что-то еще, чтобы пройтись по всем существующим записям пользователей и обновить для них эти "c:CITY"... Довольно большая работа!

  3. Проблемы с блокировкой. Пользователь «u:123» обновляет свое имя «Алекс», а пользователь «u:456» обновляет свое имя «Алекс». Они оба должны обновить «f: Alex» со своими идентификаторами. То есть либо мы сталкиваемся с проблемой перезаписывания, либо одно обновление будет ждать другого (и визуализацию, если их много?!).

Как лучше всего это сделать? Имея в виду, что я хочу искать по многим полям?

P.S. Пожалуйста, вопрос касается хранилищ HBase/Cassandra/NoSQL/Key-Value. Пожалуйста, пожалуйста - никаких советов по использованию MySQL и «чтению» SELECT; и беспокоиться о проблемах масштабирования «позже». Есть причина, по которой я задал Свой вопрос именно так, как я это сделал. :-)


person alexeypro    schedule 12.04.2010    source источник


Ответы (2)


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

Если в вашем хранилище данных нет встроенных операций индексирования или атомарных списков, вам придется решить упомянутые вами проблемы с блокировкой. Однако индексация не обязательно должна быть синхронной — поддерживайте очередь обновленных записей для переиндексации, и у вас есть решение для 3, которое можно повторно использовать и для решения 2.

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

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

person Tom Clarkson    schedule 12.04.2010
comment
Можете ли вы предложить лучший способ реализации описанной функциональности для Cassandra/HBase? Мой собственный путь - это только мое предположение, что я хотел бы узнать, каковы лучшие практики здесь. - person alexeypro; 12.04.2010
comment
Все это немного ново для реальных лучших практик, но метод, который вы описываете, довольно близок к стандарту. Основное улучшение, которое вам нужно, — это использовать любую поддержку выбранной вами платформы для списков, чтобы вы могли добавлять элементы, не загружая весь список. С Cassandra вы, вероятно, использовали бы суперстолбец. Если у вас есть чистое хранилище ключей и значений, такое как memcached, вы можете реализовать списки как значения, но вам также необходимо реализовать блокировки и, возможно, очереди. - person Tom Clarkson; 13.04.2010

Думаю, я бы реализовал это как задание MapReduce, которое будет выполняться по расписанию. Каждое искомое слово будет ключом строки с поиском по UID.

Rowkey:uid1
profile:firstName: Joe
profile:lastName: Doe
profile:nick: DoeMaster

Rowkey: uid2
profile:firstName: Jane
profile:lastName: Doe
profile:nick: SuperBabe

MapReduse индексирует все доступные для поиска свойства и добавляет их с поисковым словом в качестве ключа строки.

Rowkey: Джейн
lookup:uid: uid2

Rowkey: Doe
lookup:uid: uid2, uid1

Rowkey: DoeMaster
lookup:uid: uid1

..так далее

Теперь, если вам нужно обновить список индексов на лету в качестве изменения пользователя, вы должны записать изменение непосредственно в базу индекса, удалив значение uid из индекса и добавив к другому ключу строки. Если это происходит одновременно, может быть реализована временная блокировка.

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

Добавить дополнительное слово для поиска не очень сложно, так как речь идет именно о том, какое имя: значение вы хотите проиндексировать. вы также можете отфильтровать поиск, добавив атрибут типа к ключу/ключевому слову строки. то есть бостон - поиск: тип: город.

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

person higen    schedule 15.11.2011