Идентификатор автоинкремента в хранилище данных App Engine - PullRequest
3 голосов
/ 06 декабря 2011

Я использую хранилище данных App Engine и хотел бы убедиться, что идентификаторы строк ведут себя аналогично полям "автоинкремента" в БД mySQL.

Пробовал несколько стратегий генерации, но, похоже, не может взять под контроль то, что происходит:

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

Такое вообще возможно? Я действительно хотел бы воздержаться от хранения (индексированных) временных отметок для каждой строки.

Ответы [ 3 ]

1 голос
/ 05 марта 2012

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

Мы хотели бы удалить старые элементы (например, старше двух месяцев)

Вот модель, которая автоматически отслеживает время ее создания и модификации.Простое использование параметров auto_now_add и auto_now делает это тривиальным.

from google.appengine.ext import db

class Document(db.Model):
  user = db.UserProperty(required=True)
  title = db.StringProperty(default="Untitled")
  content = db.TextProperty(default=DEFAULT_DOC)
  created = db.DateTimeProperty(auto_now_add=True)
  modified = db.DateTimeProperty(auto_now=True)

Затем вы можете использовать cron jobs или очередь задач для планирования вашего обслуживания.задача удаления старых вещей.Найти самый старый материал так же просто, как отсортировать по дате создания или дате изменения:

db.Query(Document).order("modified")
# or
db.Query(Document).order("created")
1 голос
/ 06 декабря 2011

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

Итак, если вам нужны временные метки и приращения, добавьте поле DateTime с миллисекундами, но тогда вы не знаете, что числа уникальны.

Итак, лучше всего это сделать (что мы используем): (извините за это, но это действительно ИМХО лучший вариант)

  • использовать автоматически сгенерированный идентификатор как Long (мы используем Objectify в Java)
  • используйте временную метку для каждой сущности и используйте индекс для запроса сущностей (используйте нисходящий индекс), чтобы получить верхний X
0 голосов
/ 07 декабря 2011

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

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

class IndexEndPoint(db.Model):
    index = db.IntegerProperty (indexed = False, default = 0)

def find_next_index (cls):
    """ finds the next free index for an entity type """
    name = 'seqindex-%s' % ( cls.kind() )

    def _from_ds ():
        """A very naive way to find the next free key.

        We just take the last known end point and loop untill its free.
        """

        tmp_index = IndexEndPoint.get_or_insert (name).index

        index = None
        while index is None:
            key = db.key.from_path (cls.kind(), tmp_index))
            free = db.get(key) is None
            if free:
                index = tmp_index
            tmp_index += 1

        return index

    index = None

    while index is None:   
        index = memcache.incr (index_name)
        if index is None:  # Our index might have been evicted
            index = _from_ds ()
            if memcache.add (index_name, index):  # if false someone beat us to it
                index = None

    # ToDo:
    # Use a named task to update IndexEndPoint so if the memcache index gets evicted
    # we don't have too many items to cycle over to find the end point again.

    return index


def make_new (cls):
    """ Makes a new entity with an incrementing ID """

    result = None

    while result is None:
        index = find_next_index (cls)


        def txn ():
            """Makes a new entity if index is free.

            This should only fail if we had a memcache miss 
            (does not have to be on this instance).
            """
            key = db.key.from_path (cls.kind(), index)
            if db.get (key) is not None:
                return

            result = cls (key)
            result.put()
            return result

        result = db.run_in_transaction (txn)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...