Обратное индексирование и моделирование данных в хранилище Key-Value - PullRequest
1 голос
/ 12 марта 2020

Я новичок в key-value магазинах. Моя цель - использовать встроенное хранилище значений ключей, чтобы сохранить постоянную модель данных. Модель данных состоит из нескольких связанных таблиц, если она разработана с использованием традиционной СУБД. Я проверял среднюю статью о моделировании таблицы для хранилища значений ключей. Хотя статья использует DB уровня с Java, я планирую использовать RocksDB или FASTER с C ++ для своей работы.

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

$table_name:$primary_key_value:$attribute_name = $value

Вышеприведенное хорошо для точечного поиска, когда пользовательский код точно знает, какой ключ получить. Но существуют сценарии ios, такие как поиск пользователей, имеющих один и тот же адрес электронной почты, или поиск пользователей старше определенного возраста, или поиск пользователей одного определенного c пола. В поисковом сценарии ios статья выполняет линейное сканирование по всем клавишам. На каждой итерации проверяется шаблон ключа и применяется бизнес-логика c (проверка значения на совпадение), как только ключ с соответствующим шаблоном найден.

Похоже, что такой тип поиска неэффективен, и в худшем случае ему необходимо пройти через весь магазин. Чтобы решить эту проблему, требуется таблица обратного просмотра. У меня вопрос

Как смоделировать таблицу обратного просмотра? Это своего рода переосмысление колеса? Есть ли альтернативный способ?

Одно решение, которое легко приходит на ум, - это иметь separate ? хранилище для каждого индексируемого свойства, как показано ниже.

$table_name:$attribute_name:$value_1 = $primary_key_value 

С При таком подходе непосредственный вопрос:

Как обрабатывать коллизии в этой таблице обратного просмотра? поскольку несколько $primary_key s могут быть связаны с одним и тем же значением.

В качестве немедленного решения вместо сохранения одного значения array нескольких первичных ключей можно сохранить, как показано ниже.

$table_name:$attribute_name:$value_1 = [$primary_key_value_1, ... , $primary_key_value_N]

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

Эффективно ли хранить несколько ключей в качестве значения массива? или существует какой-то эффективный способ, предоставляемый поставщиком?

Предполагая, что строковый массив, как и дизайн, работает, такие индексы должны быть для каждого индексируемого свойства. Так что это дает точный контроль того, что индексировать, а что нет. Следующее проектное решение, которое приходит на ум, - где эти индексы будут храниться?

должны ли индексы храниться в отдельном хранилище / файле? или в том же хранилище / файле фактические данные принадлежат? Должен ли быть отдельный магазин для каждого свойства?

Для этого вопроса я понятия не имею, потому что оба эти подхода требуют более или менее одинакового количества операций ввода-вывода. Однако наличие большого файла данных будет иметь больше вещей на диске и меньше памяти (так что больше ввода / вывода), в то время как для нескольких файлов будет больше вещей в памяти, поэтому меньше сбоев страниц. Это предположение может быть полностью неверным в зависимости от архитектуры указанного хранилища значений ключей c. В то же время наличие слишком большого количества файлов превращается в проблему управления сложной файловой структурой. Кроме того, ведение индексов требует транзакций для операций вставки, обновления и удаления. Наличие нескольких файлов приводит к одному обновлению в нескольких деревьях, тогда как наличие одного файла приводит к множественному обновлению в одном дереве.

Является ли транзакция, более конкретно, транзакция, включающая несколько хранилищ / файлов, поддерживаемой?

Не только индексы - это некоторая метаинформация таблицы, которую также необходимо хранить вместе с данными таблицы. Для генерации нового первичного ключа (с автоинкрементом) необходимо предварительно знать номер последней строки или последний сгенерированный первичный ключ, потому что что-то вроде COUNT(*) не будет работать. Кроме того, поскольку все ключи не проиндексированы, информация meta может включать сведения о том, какие свойства индексируются и какие свойства не индексируются.

Как хранить метаданные каждой таблицы?

Опять тот же набор вопросов появляется и для мета таблицы. например, мета должен быть отдельным хранилищем / файлом? Кроме того, поскольку мы заметили, что не все свойства проиндексированы, мы можем даже решить сохранить каждую строку как закодированное значение JSON в хранилище данных и сохранить его вместе с хранилищами индекса. Базовый поставщик хранилища значений ключей будет рассматривать это JSON как строковое значение, подобное следующему:

$table_name:data:$primary_key_value = {$attr_1_name: $attr_1_value, ..., $attr_N_name: $attr_N_value}
...
$table_name:index:$attribute_name = [$primary1, ..., $primaryN]

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

Существуют ли недостатки использования кодированных значений JSON вместо сохранения всех свойств в качестве отдельных ключей?

Пока что я не смог найти никаких недостатков с использованием этого метода кроме принуждения пользователя к использованию кодировки JSON и некоторого выделения кучи для кодирования / декодирования JSON.

Проблемы, упомянутые выше, не указаны c для какого-либо конкретного приложения. Эти проблемы являются общими c достаточно, чтобы быть связанными со всеми разработками, использующими key-value store. Поэтому важно знать, есть ли какое-либо изобретение колеса заново.

Есть ли стандартное решение де-факто для всех проблем, упомянутых в вопросе? Отличаются ли решения от указанных в вопросе?

1 Ответ

1 голос
/ 12 марта 2020

Как смоделировать таблицу обратного просмотра? Это своего рода переосмысление колеса? Есть ли альтернативный способ?

  • Все описанные вами способы являются допустимыми способами создания индекса.
  • Он не заново изобретает колесо в RocksDB, потому что RocksDB не поддерживает индексы.
  • Это действительно зависит от данных, в общем случае вам потребуется скопировать значение индекса и первичный ключ. в другое пространство для создания индекса.

Как обрабатывать столкновения в этой таблице обратного просмотра? потому что несколько $ primary_keys могут быть связаны с одной и той же вейлом.

Вы можете сериализовать pks, используя JSON (или что-то еще). Проблема с этим подходом заключается в том, что pks становятся очень большими (что может или не может быть вещью).

Эффективно ли хранить несколько ключей в качестве значения массива? или существует какой-то эффективный способ, предоставленный поставщиком?

С RocksDB у вас нет ничего, что сделает это "проще".

Вы не упомянули следующий подход:

$table_name:$attribute_name:$value_1:$primary_key_value_1 = ""
$table_name:$attribute_name:$value_1:$primary_key_value_2 = ""
...

$table_name:$attribute_name:$value_1:$primary_key_value_n = ""

Где значение пусто. И индексированный pk является частью ключа.

должны ли индексы храниться в отдельном хранилище / файле? или в том же хранилище / файле фактические данные принадлежат? Должно ли быть отдельное хранилище для каждого свойства?

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

Является ли транзакция более конкретно транзакцией, включающей несколько хранилищ / файлов, поддерживаемых?

Only Oracle Berkeley DB и WiredTiger поддерживают эту функцию.

Как хранить метаданные каждой таблицы?

Метаданные могут находиться в базе данных или коде.

Существуют ли недостатки использования кодированных значений JSON вместо хранения всех свойств в качестве отдельных ключей?

Да, как я уже говорил выше, если вы закодировали все pks в одно значение , это может привести к проблеме вниз по течению, когда число рк велико. Например, вам нужно прочитать весь список, чтобы выполнить нумерацию страниц.

Есть ли стандартное решение по умолчанию для всех проблем, упомянутых в вопросе? Отличаются ли решения от заявленных в вопросе?

Подводя итог:

  • С RocksDB, используйте один файл базы данных
  • В индексе закодируйте первичный ключ внутри ключа и оставьте значение пустым, чтобы иметь возможность разбивать на страницы.
...