Подтвердить что ты не робот

Подходы к генерации автоматически увеличивающихся числовых идентификаторов в CouchDB

Так как CouchDB не имеет поддержки SQL как AUTO_INCREMENT, каков будет ваш подход к генерации последовательных уникальных числовых идентификаторов для ваших документов?

Я использую числовые идентификаторы для:

  • Удобные идентификаторы (например, TASK-123, RQ-001 и т.д.)
  • Интеграция с библиотеками/системами, которые требуют числовой первичный ключ

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

4b9b3361

Ответ 1

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

В обоих сценариях вы несете ответственность за создание целочисленного числа с автоматическим добавлением. Представление работает emit(the_numeric_id, null). (Вы также можете иметь пространство имен типа, например, emit([doc.type, the_numeric_id], null). Запрос для последней строки (например, с помощью startkey=MAXINT&descending=true&limit=1, увеличивать возвращаемое значение и это ваш следующий идентификатор. Попытка сохранения находится в цикле который может повторить попытку, если произошло столкновение.

Вы также можете играть в трюки, если вам не нужна 100% плотность списка идентификаторов. Например, вы можете добавить метки времени в строки emit() и оценить скорость создания документа и увеличить на эту скорость время вашего вычисления и время передачи. Вы также можете просто увеличивать на случайное целое число от 1 до N, поэтому большую часть времени первая вставка работает с ценой неоднородных идентификационных номеров.

О том, где хранить целое число, я думаю, что есть стратегия id и стратегия try и check.

Стратегия id проще и быстрее в краткосрочном. Идентификаторы документов являются целыми числами (возможно, с префиксом типа для добавления пространства имен). Поскольку Couch гарантирует уникальность в поле _id, вы просто беспокоитесь об автоматическом приращении. Сделайте это в цикле: 409 Conflict запускает повтор, 201 Accepted означает, что вы закончили.

Я думаю, что основная боль при этом заключается в том, что если и когда вы столкнетесь с конфликтами, у вас есть два полностью несвязанных документа, и один из них должен скопировать в новый документ. Если были отношения с другими документами, все они должны быть исправлены. (Приходит на ум трюк CouchDB 0.11 emit(key, {_id: some_foreign_doc_id})).

Стратегия try and check использует UUID по умолчанию как doc._id, поэтому каждая вставка будет успешной. В идеале, все или большинство ваших отношений между документами основаны на неизменяемом UUID _id, а не на целочисленном. Это просто используется для пользователей и пользовательского интерфейса. Автоматически увеличивающееся целое является просто полем в документе, {"int_id":20}. Разумеется, точка зрения emit(doc.int_id, null). (Вы можете искать документ по целочисленному id с параметром ?key=23?include_docs=true представления.

Конечно, после репликации у вас могут быть конфликты с идентификаторами (а не с официальными конфликтами CouchDB, а только с документами, использующими один и тот же числовой идентификатор). Представление, которое испускает идентификатор, также будет иметь фазу уменьшения: просто _count должно быть достаточно. Затем вы должны патрулировать БД, запросив это представление с помощью ?group=true и ищем любую строку (соответствующую целочисленному id), которая имеет счетчик > 1. С положительной стороны исправление числового идентификатора документа является незначительным изменением, поскольку он не требует создания нового документа.

Это мои идеи. Теперь, когда я записал их, я чувствую, что вы должны делать отношения-пастухи независимо от того, где хранится идентификатор; поэтому, возможно, использование _id в конце концов лучше. Единственный другой недостаток, который я вижу, - это то, что вы надолго женаты на принципиально сломанной модели именования - для некоторого определения "постоянно".

Ответ 2

Есть ли какая-либо конкретная причина, по которой вы хотите использовать числовые идентификаторы по UUID, которые CouchDB может сгенерировать для вас? UUID идеально подходят для распределенной парадигмы, которую использует CouchDB, придерживаясь встроенного.

Если вы обнаружили в своей архитектуре не более 1 CouchDB node, вы получите конфликтующие идентификаторы документов, если будете полагаться на что-то вроде "auto increment", когда наступает время для репликации. Даже если вы используете только 1 node, это, вероятно, не всегда будет иметь место, тем более что CouchDB работает так хорошо в распределенной и "автономной" архитектуре.

Ответ 3

Мне очень повезло с использованием даты форматирования iso в качестве моего ключа:

http://wiki.apache.org/couchdb/IsoFormattedDateAsDocId

Это довольно просто сделать, читаемый человеком, и в основном он создает несколько вариантов запросов только существующим.: -)

Ответ 4

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

function(doc, req) {
    if (!doc) {
        doc = {
            _id: req.id,
            type: 'idGenerator',
            count: 0
        };
    }
    doc.count++;
    return [doc, toJSON(doc.count)];
}

Включите эту функцию в проектный документ следующим образом:

{
   "_id": "_design/application",
   "language": "javascript",
   "updates": {
       "generateId": "function (doc, req) {\n\t\t\tif (!doc) {\n\t\t\t\tdoc = {\n\t\t\t\t\t_id: req.id,\n\t\t\t\t\ttype: 'idGenerator',\n\t\t\t\t\tcount: 0\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tdoc.count++;\n\t\t\t\n\t\t\treturn [doc, toJSON(doc.count)];\n\t\t}"
   }
}

Затем назовите его так:

curl -XPOST http://localhost:5984/mydb/_design/application/_update/generateId/entityId

Замените entityId тем, что вам нравится, чтобы создать несколько независимых последовательностей идентификаторов.

Ответ 5

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

Параметр skip принимает целое число, которое будет эффективно предоставлять индекс автоинкремента, к которому вы привыкли.

http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options

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

Если вашим единственным ограничением является "интеграция с библиотеками/системами, для которых требуется числовой первичный ключ", это позволит преодолеть разрыв, не теряя при этом преимуществ структуры ключа couchDB.

Ответ 6

Не идеальное решение, но что-то, что сработало для меня. Создайте независимую службу, которая генерирует автоматически увеличивающиеся идентификаторы. Да, вы, вероятно, говорите "это нарушает автономную модель couchdb", но что, если вы получите пул N идентификаторов, который вы можете использовать, когда вам нужно получить новый автоматически увеличивающийся id. Затем каждый раз, когда вы в сети, вы получаете еще больше идентификаторов, и если у вас заканчиваются иды, вы говорите своим пользователям - пожалуйста, выходите в интернет. Если пул достаточно велик (скажем, ежемесячный трафик), этого не должно произойти. Опять же, не идеально, но может быть полезно некоторым людям.