Недавно начал работать над проектом, который требует информацию о фильмах, музыке, книгах. Для этого необходимо наполнить базу данных из другого ресурса. Решил воспользоваться свободной базой данных Freebase.
Freebase — большая база знаний, содержащая структурированные данные, собранные из множества различных источников. На данный момент она насчитывает примерно 23 миллиона тем. Каждая тема ассоциирована с одним или несколькими типами (люди, места, фильмы).
Для получения данных из Freebase существует несколько вариантов:
- Скачать dump базы данных (это можно сделать тут)
- Использовать API
Постоянное восстановление из дампа отбросил сразу (хочется чего то более автоматизированного). Стал разбираться дальше. Для работы с API необходимо воспользоваться одним из 6 сервисов:
- Search Service — поиск сущностей по ключевому слову;
- Mql Read Service — извлечение детализированных данных о сущностях;
- Topic Service — извлечение всей информации о сущности;
- RDF Service — извлечение всей информации о сущности в RDF формате;
- Text Service — извлечение короткого описания для сущности;
- Image Service — получение картинки для сущности.
Первая задача которая передо мной стояла сделать autocomplete с использованием Freebase и последующей записью в свою базу данных. Для этой цели подходят два сервиса: Search Service и Mql Read Service. Выбрал второй так как с помощью него можно не только найти но и получить дополнительную информацию. Сразу же загуглил на предмет готовых либ (не люблю писать велосипеды). Все что удалось найти freebase-dotnet (использует старый API) и google-api-dotnet-client. Обе либы не реализуют асинхронных возможностей C#.
Поэтому вынужден был писать свою либу, которую можно найти здесь. Она пока ещё в бета версии, но по ходу текущего проекта я её дорабатываю и делаю стабильной, так как она будет использоваться в продакшине.
Прописав в nuget поиске Freebase4net, устанавливаем готовый package.
Чтобы пользоваться API нам надо получить ключ у Google (metaweb был куплен гуглом). Количество возможных запросов ограничено 100k запросов в день.
Для установки ApiKey мы можем сделать так
FreebaseServices.SetApiKey("YOUR API KEY");
либо так
<add key="FreebaseApiKey" value="AIzaSyC9N5HdZl15OjRcuOFxZ1SwngjCxIebbYM" />
Дальше создаем необходимый сервис:
MqlReadService readService = FreebaseServices.CreateMqlReadService();
Для поиска по имени сущности нужно отправить следующий MQL запрос, который использует regex:
[{
"type":"/music/artist",
"name":null,
"name~=":"^The Sco*$"
}]
Делается это очень просто с использованием dynamic:
dynamic films = new ExpandoObject();
films.type = "/film/film";
films.name = FreebaseHelpers.Operators.CreateLikeOperator("^The Sco*$");
Теперь собственно делаем запрос и получаем данные. Синхронно
MqlReadServiceResponse result = _readService.Read(films);
или асинхронно
MqlReadServiceResponse result = await _readService.ReadAsync(films);
Под капотом используется новый HttpClient и его асинхронные возможности.
Далее получаем имя сущности
var name = result.Results[0].name;
Results — массив dynamic. Так как ответ зависит от запроса, то есть динамический.
P.S. Существует уже готовый autocomplete, который имеет достаточно привлекательный вид и функционал. Но мне надо было сделать свою логику по кешированию данных в свою базу данных.
С autocomplete разобрались, едем дальше. Далее на странице фильма мне надо вывести описание и картинку. Для этого можно воспользоваться Topic Service, но его структура ответа достаточно сложная — надо разбираться где достать нужную информацию. Для упрощения были созданы TextService и ImageService. Поэтому решил использовать их.
string id = "/en/the_animal";
var textService = FreebaseServices.CreateTextService();
var response = await textService.ReadAsync(id);
string description = response.Result;
Получение ссылки на картинку:
string id = "/en/the_animal";
var imageService = FreebaseServices.CreateImageService();
string image = imageService.GetImageUrl(id, maxwidth: "150");
Если же вам надо сделать несколько запросов асинхронно реализован функционал.
dynamic thescorpions = new ExpandoObject();
thescorpions.name = "The Scorpions";
thescorpions.type = "/music/artist";
dynamic thepolice = new ExpandoObject();
thepolice.name = "The Police";
thepolice.type = "/music/artist";
List<MqlReadServiceResponse> multiFreebaseResponse = readService.ReadMultipleAsyncWithWait(thescorpions, thepolice);
Если у вас есть идеи как это можно было сделать лучше, буду рад их услышать.
Автор: F0rc0sigan