Как реализовать «автоинкремент» в Google AppEngine

Я должен называть что-то «сильным монотонным ростом». Будь это номера счетов, номера ярлыков доставки или тому подобное.

  1. Номер НЕ ДОЛЖЕН использоваться дважды
  2. Каждый номер ДОЛЖЕН использоваться, когда используются все меньшие числа (без отверстий).

Причудливый способ сказать: мне нужно пересчитать 1,2,3,4 … Число пробелов, которое у меня доступно, обычно составляет 100 000 номеров, и мне нужно, возможно, 1000 в день.

Я знаю, что это сложная проблема в распределенных системах, и часто мы намного лучше с GUID. Но в этом случае по юридическим причинам мне нужна «традиционная нумерация».

Может ли это быть реализовано в Google AppEngine (желательно на Python)?

  • Как я могу представить это регулярное выражение, чтобы не получить ошибку «неправильный диапазон символов»?
  • Могу ли я запретить ткани запрашивать у меня пароль sudo?
  • Перемещение легенды matplotlib за пределами оси заставляет ее обрезать блок фигуры
  • Расшифровка данных в Python, зашифрованная в 3DES с помощью Java
  • Как установить PyQt5 в Windows?
  • Как использовать класс Stitcher OpenCV с Python?
  • Firefox, начатый Selenium, игнорирует отображение, созданное pyvirtualdisplay
  • открытие сайтов с использованием urllib2 из-за корпоративного брандмауэра - 11004 getaddrinfo не удалось
  • 9 Solutions collect form web for “Как реализовать «автоинкремент» в Google AppEngine”

    Если вам абсолютно необходимо последовательно увеличивать число без пробелов, вам нужно будет использовать единый объект, который вы обновляете в транзакции, чтобы «потреблять» каждый новый номер. На практике вы будете ограничены примерно 1-5 цифрами, генерируемыми в секунду – это звучит так, как будто это будет хорошо для ваших требований.

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

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

    Gaetk – Google AppEngine Toolkit теперь поставляется с простой библиотечной функцией, чтобы получить число в последовательности. Он основан на транзакционном подходе Ника Джонсона и может быть использован довольно легко в качестве основы для подхода Мартина фон Лёвиса:

    >>> from gaeth.sequences import * >>> init_sequence('invoce_number', start=1, end=0xffffffff) >>> get_numbers('invoce_number', 2) [1, 2] 

    Функциональность в основном реализована следующим образом:

     def _get_numbers_helper(keys, needed): results = [] for key in keys: seq = db.get(key) start = seq.current or seq.start end = seq.end avail = end - start consumed = needed if avail <= needed: seq.active = False consumed = avail seq.current = start + consumed seq.put() results += range(start, start + consumed) needed -= consumed if needed == 0: return results raise RuntimeError('Not enough sequence space to allocate %d numbers.' % needed) def get_numbers(needed): query = gaetkSequence.all(keys_only=True).filter('active = ', True) return db.run_in_transaction(_get_numbers_helper, query.fetch(5), needed) 

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

    Если вы не слишком строгие в последовательности, вы можете «очертить» ваш инкремент. Это можно рассматривать как «последовательный последовательный» счетчик.

    В принципе, у вас есть одна сущность, которая является «хозяином» счетчиком. Затем у вас есть несколько объектов (на основе нагрузки, которую нужно обрабатывать), которые имеют свои собственные счетчики. Эти осколки оставляют куски ids у мастера и служат из их диапазона до тех пор, пока не исчерпываются значения.

    Быстрый алгоритм:

    1. Вам нужно получить удостоверение личности.
    2. Выбирайте осколок случайным образом.
    3. Если начало осколка меньше его конца, начинайте его и увеличивайте.
    4. Если начало осколка равно (или больше о-о) его конца, перейдите к мастеру, возьмите значение и добавьте к нему сумму n . Установите осколки, начиная с полученного значения плюс один, и заканчивая восстановленным плюсом n .

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

    редактировать

    Мне это нужно для моего приложения (вот почему я искал вопрос: P), поэтому я внедрил свое решение. Он может захватывать отдельные идентификаторы, а также эффективно захватывать партии. Я тестировал его в контролируемой среде (на appengine), и он выполнялся очень хорошо. Вы можете найти код на github .

    Помните: Sharding увеличивает вероятность того, что вы получите уникальное значение auto-increment, но не гарантирует его. Пожалуйста, возьмите совет Ника, если вы ДОЛЖНЫ иметь уникальное автоматическое вмешательство.

    Я применил для своего блога что-то очень упрощенное, которое увеличивает IntegerProperty, iden а не идентификатор ключа.

    Я определяю max_iden() чтобы найти максимальное число iden настоящее время используется. Эта функция просматривает все существующие сообщения в блоге.

     def max_iden(): max_entity = Post.gql("order by iden desc").get() if max_entity: return max_entity.iden return 1000 # If this is the very first entry, start at number 1000 

    Затем, создавая новое сообщение в блоге, я назначаю ему свойство max_iden() + 1

     new_iden = max_iden() + 1 p = Post(parent=blog_key(), header=header, body=body, iden=new_iden) p.put() 

    Интересно, можно ли после этого добавить к вам какую-то функцию проверки, то есть убедиться, что max_iden () теперь увеличился, прежде чем перейти к следующему счету.

    В целом: хрупкий, неэффективный код.

    В качестве альтернативы вы можете использовать allocate_ids (), как предложили люди, а затем создать эти объекты спереди (т. Е. С помощью значений свойств заполнитель).

     first, last = MyModel.allocate_ids(1000000) keys = [Key(MyModel, id) for id in range(first, last+1)] 

    Затем, создав новый счет, ваш код может пропустить эти записи, чтобы найти тот, у которого самый низкий идентификатор, так что свойства placeholder еще не были перезаписаны реальными данными.

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

    Я думаю, используя следующее решение: используйте CloudSQL (MySQL), чтобы вставить записи и назначить последовательный идентификатор (возможно, с помощью очереди задач), позже (используя задачу Cron) переместите записи CloudSQL обратно в хранилище данных.

    Сущности также могут иметь UUID, поэтому мы можем сопоставить объекты из хранилища данных в CloudSQL, а также иметь последовательный идентификатор (по юридическим причинам).

    Python - лучший язык программирования в мире.