Загрузка данных (Dataloader)¶
Загрузчик данных Dataloader
это универсальная утилита, которая будет использоваться как часть слоя данных вашего приложения для предоставления упрощенного и консистентного API под различные источники данных, такие как базы данных или веб-сервисы, посредством пакетной обработки и кэширования.
Пакетная обработка (Batching)¶
Пакетная обработка это основная функция DataLoader
. Создайте загрузчик, определив функцию пакетной обработки.
from promise import Promise
from promise.dataloader import DataLoader
class UserLoader(DataLoader):
def batch_load_fn(self, keys):
# Here we return a promise that will result on the
# corresponding user for each key in keys
return Promise.resolve([get_user(id=key) for key in keys])
Функция пакетной обработки принимает список ключей и возвращает Promise
, который резолвит список значений.
Затем загрузите значения из загрузчика. DataLoader
объединит отдельные загрузки, которые происходят в одном фрейме (выполняется после того, как Promise
разрешится), а затем вызовет функцию пакетной обработки со всеми запрошенными ключами.
user_loader = UserLoader()
user_loader.load(1).then(lambda user: user_loader.load(user.best_friend_id))
user_loader.load(2).then(lambda user: user_loader.load(user.best_friend_id))
Наивное приложение может запросить сервер 4 раза , но с DataLoader
данное приложение сделает максимум 2 запроса.
DataLoader
позволяет Вам отделить несвязанные части Вашего приложения без ущерба для производительности пакетной загрузки данных. В то время как загрузчик предоставляет API, который загружает отдельные значения, все конкурентные запросы будут объединены и представлены в вашу функцию пакетной обработки. Это позволяет вашему приложению безопасно распределять запросы к получению данных во всем приложении и поддерживать минимальное количество исходящие запросов.
Использование с Graphene¶
DataLoader
хорошо сочетается с Graphene / GraphQL.
Поля GraphQL спроектированы для автономных(stand-alone) функций. А без механизма кэширования или пакетной обработки наивный сервер GraphQL будет генерировать новые запросы к базе данных каждый раз при резолве поля.
Рассмотрим следующий запрос GraphQL:
{
me {
name
bestFriend {
name
}
friends(first: 5) {
name
bestFriend {
name
}
}
}
}
Если каждый из me
,bestFriend
и friends
запросит сервер, то получится 13 запросов к базе данных.
При использовании DataLoader
, мы могли бы определить тип User
, используя предыдущий пример, более компактно и с не более, чем 4 запросами к базе данных, а то и меньше, если использовать кеширования.
class User(graphene.ObjectType):
name = graphene.String()
best_friend = graphene.Field(lambda: User)
friends = graphene.List(lambda: User)
def resolve_best_friend(self, info):
return user_loader.load(self.best_friend_id)
def resolve_friends(self, info):
return user_loader.load_many(self.friend_ids)