Поиск (и общие запросы) с помощью HBase и / или Cassandra (лучшие практики?) - PullRequest
2 голосов
/ 12 апреля 2010

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

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

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

u: 123456789 = serialized_json_object

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

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

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

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

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

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

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

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

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

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

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

Ответы [ 2 ]

4 голосов
/ 12 апреля 2010

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

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

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

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

1 голос
/ 15 ноября 2011

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

RowKey: UID1
профиль: имя: Джо
профиль: фамилия: Доу
профиль: ник: DoeMaster

Rowkey: uid2
Профиль: Имя: Джейн
профиль: фамилия: Доу
профиль: ник: SuperBabe

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

Роуки: Джейн
поиск: uid: uid2

Rowkey: Доу
поиск: uid: uid2, uid1

Rowkey: DoeMaster
поиск: uid: uid1

.. и т.д.

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

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

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

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

...