Таблица поиска GAE несовместима с транзакциями?

Моему приложению Python High Replication Datastore требуется большая таблица поиска от 100000 до 1 000000 записей. Мне нужно иметь возможность предоставить код некоторому методу, который будет возвращать значение, связанное с этим кодом (или None, если нет связи). Например, если моя таблица содержит приемлемые английские слова, я бы хотел, чтобы функция возвращала True, если слово было найдено, и False (или None) в противном случае.

Моя текущая реализация состоит в том, чтобы создать один объект без родителей для каждой записи таблицы, и чтобы этот объект содержал любые связанные данные. Я установил ключ хранилища данных для этой сущности так же, как мой код поиска. (Я помещаю все сущности в их собственное пространство имен, чтобы предотвратить любые конфликты клавиш, но это не существенно для этого вопроса.) Затем я просто вызываю get_by_key_name() в коде и получаю связанные данные.

Проблема в том, что я не могу получить доступ к этим объектам во время транзакции, потому что я буду пытаться охватить группы объектов. Итак, возвращаясь к моему примеру, скажем, я хотел проверить правописание всех слов, используемых в сеансе чата. Я мог получить доступ ко всем сообщениям в чате, потому что я дал бы им общего предка, но я не мог получить доступ к своей таблице слов, потому что записи там не содержат родителей. Крайне важно, чтобы я мог ссылаться на таблицу во время транзакций.

Обратите внимание, что моя таблица поиска исправлена ​​или изменяется очень редко. Опять же, это соответствует примеру проверки орфографии.

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

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

Хранение записей таблицы в memcache заманчиво, но это тоже имеет проблемы. Это большой объем данных, но более проблематичным является то, что если GAE загрузит запись memcache, я не смогу перезагрузить ее во время транзакции.

Кто-нибудь знает подходящую реализацию для больших глобальных таблиц поиска?

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

2 ответа

Решение

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

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

Аналогично, если он слишком велик, чтобы его можно было использовать в качестве статического ресурса, вы можете использовать тот же подход, что и выше, но хранить данные в хранилище больших двоичных объектов.

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

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

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

Во-первых, если вы уверены, что пространство имен поможет избежать столкновений клавиш, пришло время сделать шаг назад. Ключ состоит из вида объекта, пространства имен, имени или идентификатора и любых родителей, которые могут быть у объекта. Вполне допустимо, чтобы два разных типа сущностей имели одно и то же имя или идентификатор. Так что если у вас есть, скажем, LookupThingy с которым вы сопоставляете, и создали каждого участника, указав уникальное имя, ключ не столкнется ни с чем другим.

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

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

Другие вопросы по тегам