Какие-либо стратегии для оценки компромисса между потерей процессора и выигрышем памяти от сжатия данных, хранящихся в TextProperty модели хранилища данных? - PullRequest
2 голосов
/ 06 апреля 2010

Являются ли очень большие TextProperties бременем? Должны ли они быть сжаты?

Скажем, у меня есть информация, хранящаяся в 2 атрибутах типа TextProperty в моих сущностях хранилища данных. Строки всегда имеют одинаковую длину 65 000 символов и имеют много повторяющихся целых чисел, пример выглядит следующим образом:

entity.pixel_idx   = 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,5,5,5,5,5,5....etc.
entity.pixel_color = 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,...etc.

Таким образом, все вышесказанное также можно представить с использованием гораздо меньшего объема памяти хранения, сжимая, скажем, используя только каждое целое число и длину его серии ('0,8' for '0,0,0,0,0,0,0,0'), но тогда требуется время и ЦП для сжатия и распаковки? Есть общие идеи? Существуют ли уловки для проверки различных попыток решить проблему?

Ответы [ 2 ]

4 голосов
/ 06 апреля 2010

Если все ваши целые числа являются однозначными числами (как в вашем примере), то вы можете уменьшить объем памяти в два раза, просто пропустив запятые.

Краткий ответ

Если вы ожидаете много повторений, тогда имеет смысл сжимать ваши данные - ваши данные не такие маленькие (65 КБ) и очень повторяющиеся => они будут хорошо сжиматься. Это сэкономит вам место для хранения и сократит время, необходимое для передачи данных обратно из хранилища данных, когда вы запрашиваете его.

Длинный ответ

Я провел небольшое тестирование, начиная с предоставленной вами короткой примерной строки, и эта же строка повторялась до 65000 символов (возможно, более повторяющихся, чем ваши фактические данные). Эта строка сжата с 65K до нескольких сотен байтов; Возможно, вы захотите провести дополнительное тестирование в зависимости от того, насколько хорошо сжимаются ваши данные.

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

  • Время API занимает в 10 раз меньше для одного объекта (41 мс против 387 мс в среднем)
  • Используемое хранилище значительно меньше (поэтому похоже, что GAE не сжимает ваши данные).
  • Неожиданно процессорное время уменьшается примерно на 50% (130 мс против 180 мс при извлечении 100 сущностей). Я ожидал, что процессорное время будет немного хуже, поскольку сжатые данные должны быть несжатыми. Должна быть какая-то другая работа ЦП (например, декодирование буфера протокола), которая еще больше загружает ЦП для гораздо больших несжатых данных.
  • Эти различия означают, что время настенных часов также значительно быстрее для сжатой версии (<100 мс против 426 мс при извлечении 100 объектов). </li>

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

from google.appengine.ext import db
import zlib
class CompressedDataProperty(db.Property):
  """A property for storing compressed data or text.

  Example usage:

  >>> class CompressedDataModel(db.Model):
  ...   ct = CompressedDataProperty()

  You create a compressed data property, simply specifying the data or text:

  >>> model = CompressedDataModel(ct='example uses text too short to compress well')
  >>> model.ct
  'example uses text too short to compress well'
  >>> model.ct = 'green'
  >>> model.ct
  'green'
  >>> model.put() # doctest: +ELLIPSIS
  datastore_types.Key.from_path(u'CompressedDataModel', ...)

  >>> model2 = CompressedDataModel.all().get()
  >>> model2.ct
  'green'

  Compressed data is not indexed and therefore cannot be filtered on:

  >>> CompressedDataModel.gql("WHERE v = :1", 'green').count()
  0
  """
  data_type = db.Blob

  def __init__(self, level=6, *args, **kwargs):
    """Constructor.

    Args:
    level: Controls the level of zlib's compression (between 1 and 9).
    """
    super(CompressedDataProperty, self).__init__(*args, **kwargs)
    self.level = level

  def get_value_for_datastore(self, model_instance):
    value = self.__get__(model_instance, model_instance.__class__)
    if value is not None:
      return db.Blob(zlib.compress(value, self.level))

  def make_value_from_datastore(self, value):
    if value is not None:
      return zlib.decompress(value)
0 голосов
/ 06 апреля 2010

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

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

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

В качестве альтернативы, вы можете подождать, пока не появятся Ник или Алекс, и они, возможно, скажут вам, сжаты ли данные в хранилище данных.

...