Кэширование отчетов в скользящем окне - PullRequest
0 голосов
/ 08 мая 2020

У меня есть конечная точка api, которая принимает в качестве входных данных некоторые данные с полями «date_from» и «date_to».

Когда запрос сделан, он инициирует создание отчета. Эти поля «date_from» и «date_to» используются для генерации (date_to - date_from).days количества подзапросов. На основе каждого из этих подзапросов генерируется ha sh, который используется либо для получения подответа из базы данных redis с помощью ha sh, либо для составления некоторых уравнений с последующим сохранением этого подответа в redis. В конце все подответы агрегируются и возвращаются как фактический ответ.

У меня был вариант использования, когда все данные уже хранятся в redis, но на длинных диапазонах date_to и date_from все равно (date_to - date_from).days количество запросов к базе данных кеша. Поэтому я решил также сохранить окончательный ответ на запрос в redis таким же образом, создав ha sh.

Моя проблема в том, что эти отчеты создаются регулярно с помощью скользящего окна date_from и date_to. Например, вчера было date_from = "2017-03-08" date_to = "2020-05-07", а сегодня было бы date_from = "2017-03-09" date_to = "2020-05-08". Это означает, что

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

Вот мой код

def generate_report(self, serialized_data):
    result = {
            'deviation' : []
             }
    total_hash = hashlib.sha256(str(serialized_data).encode()).hexdigest()
    total_target = self.redis.get(total_hash)
    if not total_target:
        for date_from, date_to in self.date_range:
            serialized_data['media_company']['date_from'] = \
                                                date_from.strftime("%Y-%m-%d")
            serialized_data['media_company']['date_to'] = \
                                                date_to.strftime("%Y-%m-%d")
            hash = hashlib.sha256(str(serialized_data).encode()).hexdigest()
            target = self.redis.get(hash)
            media_company, context, validator = \
                                    self.prepare_for_validation(serialized_data)
            if not target:
                target = validator.check({'media_company': media_company, **context})
                self.redis.setex(hash, timedelta(days=180), json.dumps(target))
            else:
                self.redis.expire(hash, timedelta(days=180))
                target = json.loads(target)

            result['deviation'].append(target['deviation'])
            result['date'] = [str(date_to) for date_from, date_to in self.date_range]
        total_target = result
        self.redis.setex(total_hash, timedelta(days=180), json.dumps(total_target))
    else:
        total_target = json.loads(total_target)
    return total_target

total_ha sh представляет ха sh исходных данных,

self.date_range представляет массив диапазонов дат для подзапросов,

ha sh представляет ha sh для подзапросов

Не могли бы вы порекомендовать лучший способ кэширования данных или могут быть способы ускорить этот алгоритм?

1 Ответ

1 голос
/ 08 мая 2020

Вы можете рассмотреть возможность использования конвейера redis вместо отдельных команд get в l oop, я не уверен в коде python, как это сделать, но следующий прототип может помочь вам

p1 = self.redis.pipeline()
if not total_target:
  for date_from, date_to in self.date_range:
     #use pipeline here to get target for each day.
     hash = hashlib.sha256(str(serialized_data).encode()).hexdigest()
     p1.get(hash)

#use other pipeline here to set values and expires base on result
#also compute target_toal
p2 = self.redis.pipeline()
for result in p1.execute():
   if not result:
      -- p2 set value with expiry
   else
      -- p2 set expiry
...