Недавно начал работать над проектом, который требует информацию о фильмах, музыке, книгах. Для этого необходимо наполнить базу данных из другого ресурса. Решил воспользоваться свободной базой данных 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);
Если у вас есть идеи как это можно было сделать лучше, буду рад их услышать.

