MQL

Материал из Российская школа по Semantic Web
Перейти к: навигация, поиск
MQL
Номер 7
Лектор Катков Ю.В.
Prerequisites JSON
Замечание структура сейчас довольно рыхлая. Надо начинать с ядра MQL - разных видов запросов значений и вложенных объектов, а потом уж переходить на мелочи вроде директив. Нужно перестроить конспект
Аннотация Рассмотрена свободная база знаний Freebase от Google Metaweb. Сначала мы вспомним JSON и покажем несколько запросов. Затем мы познакомимся со структурой Freebase и начнем писать MQL-запросы нарастающей мощи. В конце рассматриваются API Freebase и возможности её использования на своих сайтах.

В ходе этой лекции мы рассмотрим свободную базу знаний Freebase и то, как использовать язык запросов Metaweb Query Language (MQL).

Содержание

Введение

Интерфейс запросов SPARQL поддерживается огромным количеством различных хранилищ, а вот язык MQL, о котором пойдет речь, используется только в базе знаний Freebase. Однако, это нисколько не умаляет важности изучения MQL всеми разработчиками семантических приложений, т.к. его нераспространенность и закрытость с лихвой компенсируется высоким качеством и огромным объемом данных, хранящимся во Freebase.

Изначально Freebase была проектом, занимающимся извлечением структурированных данных из Википедии. В 2008 году её создатели, компания Metaweb, выпустили коротенькую статью с описанием проекта, на чем и закончилась их серия академических публикаций. На момент написания статьи Freebase включает 22 745 088 понятий и использует данные из различных открытых источников. [1]

Freebase использует закрытый сервер баз данных Metaweb, однако все данные являются свободными и могут быть экспортированы в RDF или скачаны в виде дампов. Однако основным способом доступа к информации Freebase является, все же, их собственный язык запросов MQL.

JSON

Старина Лео поможет нам разобраться с тем, как помещать объекты в фигурные скобочки

MQL-запросы и ответы на них являются JSON-объектами, поэтому сначала стоит рассказать о JSON. JSON (JavaScript Object Notation) - это язык, созданный для обмена данными в формате "ключ-значение". Изначально JSON использовался для сериализации объектов JavaScript, но быстро стал языконезависимым и благодаря своей простоте, стал очень любим и уважаем программистами на разных языках и платформах.

Самый простой JSON-объект - пустой объект. Он записывается следующим образом:

{}

Теперь давайте создадим объект, в котором хранится информация о Леонардо да Винчи. Для начала ограничимся только его именем. Для этого заключим ключ и значение в кавычки, разделив двоеточием

{
 "name" : "Leonardo di ser Piero da Vinci"
}

Добавляем несколько фактов о Леонардо, разделяя их через запятую:

{
 "name" : "Leonardo di ser Piero da Vinci",
 "date_of_birth": "1453-04-15",
}

Теперь стоит определить, что за профессия была у да Винчи. А профессий-то этих было много: и скульптор, и художник, и архитектор и еще много кто! Для того, чтобы присвоить одному ключу несколько значений, в JSON используются списки значений - заключенные в квадратные скобки значения, указанные через запятую:

{
 "name" : "Leonardo di ser Piero da Vinci",
 "date_of_birth": "1453-04-15",
 
 "profession": [
      "Architect",
      "Engineer",
      "Anatomist",
      "Inventor",
      "Artist",
      "Sculptor"
    ],
}

Еще одна вещь о JSON, которую стоит знать, - это вложенные объекты. Они делаются крайне просто: после ключа вы просто вставляете новый набор пар ключей-значений в фигурных скобках. В случае с Леонардо мы можем попробовать отобразить данные о месте рождения Леонардо - селе Анкиано, находящемся в Италии. Мы скажем, что ключ "place_of_birth" соответствует некоторому объекту с именем Anchiano, находящимся в Italy :

{
 "name" : "Leonardo di ser Piero da Vinci",
 "date_of_birth": "1453-04-15",
 "profession": [
      "Architect",
      "Engineer",
      "Anatomist",
      "Inventor",
      "Artist",
      "Sculptor"
    ],
 
 "place_of_birth": {
      "name": "Anchiano",
      "containedby": "Italy",
   },
}

JSON во Freebase

Перейдем теперь на Freebase и посмотрим, как там хранится информация. Для этого сначала перейдем на страничку описания Леонардо да Винчи (её легко найти, введя в поиске Leonardo). В самом низу этой страницы есть кнопка Edit and Show details по которой мы попадем в режим редактирования Freebase. Это, однако, не единственный способ отображения информации - в самом низу страницы, вы можете просмотреть свойства объекта Леонардо да Винчи в виде списка, а также в форматах RDF и JSON.

Нам наиболее интересен последний способ, и для того, чтобы увидеть Леонардо в виде JSON, пройдите по ссылке. Просмотрите JSON-код и убедитесь, что нотация хорошо понятна.

Первые шаги в MQL

Редактор запросов

В своих приложениях, общение с серверами Freebase будет вестись, скорее всего, посредством подробно описанных API, но знакомиться с MQL лучше всего, используя редактор запросов.

Вот его адрес: http://www.freebase.com/queryeditor

Редактор этот страшно удобен и имеет прекрасную функцию автодополнения запросов -- в случае затруднений просто нажмите Ctrl+Enter и вы получите отличные контекстные подсказки. В нижней панели редактора расположились полезные инструменты, которые подробно описаны в руководстве [2]. При самостоятельном изучении особенно советуем поглядеть на кнопку examples, содержащую примеры запросов, проясняющим многие возможности MQL. MQL query editor.png

Первый запрос

Сначала поупражняемся с редактором запроса. Начнем с самого простого запроса: попробуем найти Леонардо да Винчи во Freebase и узнаем дату его рождения. Для этого зайдите в MQL query editor и введите там следующее:

{
  "id":   "/en/leonardo_da_vinci",
  "/people/person/date_of_birth" : null
}

Полезно ввести этот запрос вручную, для того, чтобы привыкнуть к услужливому редактору запросов. Введите весь текст вплоть до двоеточия после id и наберите Leonardo. Затем нажмите Ctrl+Enter и выберите того Леонардо, который вам больше нравится, а именно /en/leonardo_da_vinci . MQL Editor сам позаботится о кавычках и запятых.

Затем перейдите на новую строку и введите date. Нажмите Ctrl+Enter для того, чтобы получить список свойств, связанных с типом Леонардо. Среди них одной из первых будет /people/person/date_of_birth - выберите её и вы увидите, что query editor добавил к запросу ": null".

Анализ запроса

Разберем этот запрос подробнее. Мы указали идентификатор объекта во Freebase с помощью термина "id". Идентификаторы есть у всех объектов, а слово id является сокращением от "/type/object/id" . Есть много других /type/object свойств, которыми обладают все сущности Freebase, они будут рассмотрены чуть позже.

Объект, имеющий идентификатор "/en/leonardo_da_vinci", возможно, обладает свойством "/people/person/date_of_birth", значения которого мы не знаем. Мы ставим вместо этого значения специальное слово null, на место которого в ответе Freebase запишет значение из базы.

Как легко заметить, запрос и ответ на него симметричны:

Запрос Ответ
  1. {
  2.   "id":     "/en/leonardo_da_vinci",
  3.   "/people/person/date_of_birth" : null
  4. }
  1. {
  2.     "id":   "/en/leonardo_da_vinci"
  3.     "/people/person/date_of_birth": "1453-04-15",
  4.   }

Freebase logo.png

Сложный запрос

Теперь, для того, чтобы возникло побольше вопросов, мы составим достаточно сложный MQL-запрос и вкратце его объясним. После этого можно будет приступить к подробному изучению структуры Freebase и обзору возможностей языка.

Итак, вот наш запрос (взят из руководства по MQL):

Запрос Ответ
  1. [{
  2.   "type":    "/music/album",
  3.   "name":    null,
  4.   "name!=":  "Greatest Hits",
  5.   "release_date|=": [
  6.     "1978",
  7.     "1979"
  8.   ],
  9.   "genre":[],
  10.   "a:genre": "New Wave",
  11.   "b:genre|=": [
  12.     "Punk Rock",
  13.     "Post-punk",
  14.     "Progressive rock"
  15.   ],
  16.   "artist": {
  17.     "name": null,
  18.     "type": {
  19.       "id":       "/people/person",
  20.       "optional": "forbidden"
  21.     }
  22.   },
  23.   "limit":2,
  24.   "sort":"name",
  25. }]
  1. [{
  2.     "type":     "/music/album",
  3.     "name":     "Dawn of the Dickies",
  4.     "a:genre":  "New Wave",
  5.     "artist": {
  6.       "name": "Television",
  7.       "type": null
  8.     },
  9.     "genre": [
  10.       "Punk rock",
  11.       "New Wave",
  12.       "Post-punk",
  13.       "Protopunk"
  14.     ],
  15.     "ns0:name": "Adventure",
  16.     "ns1:type": "/music/album"
  17.   },
  18.   {
  19.     "a:genre": "New Wave",
  20.     "artist": {
  21.       "name": "The Dickies",
  22.       "type": null
  23.     },
  24.     "genre": [
  25.       "New Wave",
  26.       "Punk rock"
  27.     ]
  28. }]

Freebase logo.png

Попробуем вкратце описать, что за средства MQL использованы в данном запросе.

Во-первых, как можно видеть, весь запрос обернут в конструкцию [ { } ], что означает, что в качестве результата вы ожидаете список объектов, а не один объект, как в случае с { }.

Строки 2-4 не должны вызывать каких-либо проблем: мы ищем объект типа альбом (/music/album), нам хочется получить его имя и нас не интересуют альбомы, называющиеся "Greatest Hits".

В строчках 5-8 и 11-15 появляется оператор ИЛИ |= - нас интересуют альбомы, у которых дата выхода равна 1978 или 1979 году. Перейдем теперь к жанру:

  1.   "genre":[],
  2.   "a:genre": "New Wave",
  3.   "b:genre|=": [
  4.     "Punk Rock",
  5.     "Post-punk",
  6.     "Progressive rock"
  7.   ],

Первая строчка говорит о том, что нам хочется получить список жанров данных альбомов в ответе запроса. Для этого мы добавили в запрос пустой список [ ]. Дальше мы говорим, что нас интересуют только альбомы, в жанрах которых указаны New Wave И один из списка "Punk Rock", "Post-punk", "Progressive rock".

Наконец, строки 23-24 содержат директивы MQL: мне интересны только два результата (limit) и я хочу отсортировать их по имени (sort).

Немного об устройстве Freebase

Вообще-то движок, на котором работает Freebase называется Metaweb - так же как и название компании. Однако, он не открыт, его нельзя скачать, да и кроме Freebase, никакая другая база знаний его не использует - так зачем путаться? Мы будем говорить о Freebase, имея в виду и базу, и сервер БД Metaweb.

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

Прежде чем приступить к написанию MQL-запросов, стоит совсем немного рассказать об устройстве Freebase.

Идентификация объектов

Итак, Freebase позволяет нам думать о том, что внутри него лежат объекты. Каждый объект ограничивается фигурными скобками {} и состоит из пар "свойство-значение_свойства", разделенных двоеточиями. Объекты, которые Freebase выдает в качестве ответов на MQL-запросы, являются корректными JSON-объектами, однако они не похожи на объекты парадигмы ООП. Лучше всего думать о них, как о неупорядоченных множествах пар.

В качестве свойство (то есть того, что стоит до двоеточия) в MQL могут стоять идентификаторы. В качестве значений могут быть идентификаторы, литералы, массивы и, наконец, вложенные объекты.

Freebase имеет правила, по которым должны строиться идентификаторы. Идентификатор состоит из пространства имен и ключа, разделенных прямым слэшем /. Рассмотрим, например, идентификатор /people/person/date_of_birth - в нем date_of_birth является ключом, а /people/person - пространством имен.

Идентификаторы уникальны. Они не обязаны нести смысловой нагрузки, однако зачастую по идентификатору объекта легко понять, о чем идет речь. Date of birth.png

Универсальные свойства объектов

Все объекты Freebase обладают следующими зарезервированными (универсальными свойствами). Вот полный список: имя, ключ, идентификатор, типы, временя создания, создатель, режим доступа, глобальный идентификатор. Мы рассмотрим тут свойства, которые наиболее часто используются в MQL-запросах: имена, идентификаторы и типы.

Свойство /type/object/id

Именно это свойство позволяет однозначно идентифицировать объекты. У объекта есть всего один идентификатор и не бывает двух объектов с одинаковыми идентификаторами. Так например, взгляните, как многих людей звали Адам Смит (Adam Smith): статья на английской википедии . Только моральный философ Адам Смит носит гордый идентификатор /en/adam_smith. Все остальные Адамы Смиты будут идентифицироваться по другому, будь они политиками (/en/adam_smith_1965), футболистами (/en/adam_smith_huddersfield) или кем-либо другим.

Свойство /type/object/name

У каждого объекта есть имя. Имя - вещь не уникальная, у объекта обычно несколько имен - по одному на каждый язык. Самое интересное, что это нисколько не усложняет запросы - вы заметите, что при запросе имен вам будет выдаваться только имя на языке, установленном во Freebase как текущий. Так что можно обращаться с объектами типа name как с обычными строками.

Свойство /type/object/type

Это свойство задает тип объекта. У одного объекта может быть несколько типов - обычно так и бывает.

Свойства в пространстве имен /type/object можно сокращать, отбрасывая пространство имен. Взгляните, например, на этот запрос объектов с идентификатором "Папа Римский", выдающий всех людей с этой профессией:

Запрос Ответ
  1. {
  2.   "id": "/en/pope",
  3.   "/people/profession/people_with_this_profession": [{
  4.     "name":  null,
  5.     "limit": 4
  6.   }]
  7. }
  1. {
  2.     "id": "/en/pope"
  3.     "/people/profession/people_with_this_profession": [
  4.       { "name": "Saint Peter"    },
  5.       { "name": "Pope Linus"     },
  6.       { "name": "Pope Anacletus" },
  7.       { "name": "Pope Clement I" }
  8.     ],
  9.   }

Freebase logo.png

Мы пишем "id" и интерпретатор MQL понимает, что имеется в виду /type/object/id. Как мы увидим дальше, интерпретатор MQL прощает и не такие вольности.

Язык MQL

Metaweb query language - это прекрасный язык запросов, основанный на JSON и по мощи сопоставимый со SPARQL 1.0. Он, однако, не стандартизирован, и не используется за пределами Freebase.

В реальной жизни, если ваше приложение использует Freebase, вы скорее всего будете посылать MQL-запросы как GET-параметры HTTP. Вот небольшой пример использования запросного сервиса - зададим тот же самый вопрос про пап римских (скопируйте запрос в адресную строку или [{%22name%22:%20%20null,%22limit%22:%204}}} пройдите по ссылке]):

https://api.freebase.com/api/service/mqlreadquery={"query":
 {"id": "/en/pope","/people/profession/people_with_this_profession": [{"name":  null,"limit": 4}]}}

Для подробностей по использованию REST API Freebase почитайте главу Metaweb Read Service. А тут мы углубимся в собственно язык запросов.

Не совсем JSON

Во-первых, MQL-запросы не являются корректными JSON-объектами, а лишь преобразуемыми к JSON. Одна из идей продуктов Metaweb заключается в том, что программы должны уметь прощать пользователям ошибки и описки, которые те делают. Эта идея есть и в других языках и программах, а в первую очередь - в World Wide Web - ничего страшного, что некоторые части html написаны с ошибками, нужно все равно постараться отобразить документ.

Запрос наших Пап может быть написан в любом из форматов

Корректный JSON Нет кавычек
{
   "id": "/en/pope",
   "/people/profession/people_with_this_profession": [{
   "name":  null,
   "limit": 4
  }]
}
{
   id: /en/pope,
   /people/profession/people_with_this_profession: [{
   name:  null,
   limit: 4
  }]
}
А вот пример совсем уж безобразия
   id /en/pope
   /people/profession/people_with_this_profession [{
   name  null
   limit 4

Обратите внимание на последний пример: мы не вставили ни одного разделителя, забыли кавычки и даже не позаботились ни о каких скопках, кторе тех, что важны для понимания смысла запроса. Приятно работать с системой, умеющей прощать.

Когда можно говорить кратко

Ранее мы рассматривали корректные идентификаторы, состоящие из пространства имен и ключа. Стрелянный читатель мог насторожиться, почему в запросах, что мы приводили выше, почти отсутствует UNIX-подобная нотация записи идентификаторов. Тут мы снова видим то, как разработчики Freebase постарались облегчить нам жизнь: довольно часто пространство имен в идентификаторе можно опускать.

Рассмотрим запрос всех фильмов, снятых Стэнли Кубриком. Слева показан запрос в сокращенной форме, которой мы и будем пользоваться дальше, а справа - то, как он мог бы выглядеть, не будь разработчики Metaweb так добры к нам.

Оригинальный запрос Очень правильный запрос
  1. [{
  2.   "name": "Stanley Kubrick",
  3.   "type": "/film/director",
  4.   "film": [],
  5. }]
  1. [{
  2.   "/type/object/name": "Stanley Kubrick",
  3.   "/type/object/type": "/film/director",
  4.   "/film/director/film" : []
  5. }]

Во первых, если мы явно указываем тип объекта (свойство type), то мы можем опускать все свойства, относящиеся к этому типу. Какие свойства относятся к типу /film/director? Разумеется, те, которые находятся в пространстве имен этого типа, то есть те, что начинаются с /film/director. Попробуйте выкинуть из оригинального запроса третью строку - вы увидите, что он не сработает.

Во-вторых, все свойства из пространства имен /type/object можно опускать - именно поэтому мы имеет право писать просто id, name, type и т.д. Догадайтесь, почему это возможно?

Виды запросов неизвестных значений

После того как мы отведали синтаксического сахара MQL, самое время приступить к изучению его конструкций. В первую очередь, давайтепосмотрим на то, как в MQL запрашиваются нужные значения.

Запрос одного значения

Если вы хотите, чтобы Freebase вернул вам объект той же структуры, что и объект запроса, но с заполненным неизвестным полем, то в запросе надо вместо этого поля подставить null. Мы видели довольно много таких примеров.

Запрос массива значений

Очень часто нам нужно получить не одно значение, а целый список. В этом случае в качестве искомого нужно подставить пустой массив []. Freebase заполнит этот массив строками, перечисленными через запятую.

Напрашивается вопрос – а как же обстоит дело с ошибками в запросах? Если в качестве свойства какого-либо объекта стоит массив значений, а вы запрашиваете это свойство, как одиночное значение (через null) - вы и правда получите ошибку.

ПРИМЕР

Если вы напротив, запросите массив вместо одиночного значения – в этот нет никаких проблем – Freebase преобразует результаты и выдаст массив с одним-единственным значением.

ПРИМЕР

Запрос объектов

Тем, кто знаком со SPARQL могло показаться, что структура Freebase слишком уж проста – слишком уж часто значениями свойств оказываются обыкновенные строки. Но на самом деле все обстоит несколько сложнее. Во Freebase все является объектом и у нас всегда есть возможность запросить значения как объекты. Сначала мы покажем, как пользоваться этим полиморфизмом, а в главе Свертка объектов, объясним сам механизм.

Вложенные запросы

Итак, если вам хочется получить нечно большее, чем просто имя объекта, в качестве искомого объекта нужно подставлять не null, а использовать вложенные подзапросы, ограниченные фигурными скобками { }.

ПРИМЕР

Массивы вложенных запросов

В тех случаях, когда то или иное свойство содержит несколько значений, и нам нужна информация о них всех, нужно заключить наш вложенный запрос в массив [{ вложенный запрос}]. Предположим, мы хотим узнать…

ПРИМЕР

Запрос краткой информации об объекте

Есть еще одна форма запроса вложенных объектов, когда вместо искомого значения подставляется пустой объект {} или массив пустых объектов [{}]. Этот запрос работает по-разному в зависимости от того, что за тип у искомого объекта. Мы покажем в табличке три запроса:

ПРИМЕР

Свертка объектов

Может показаться, что мы разворачиваем строковые значения в объекты, но на деле все обстоит строго противоположным образом - во Freebase всё является объектом и способно сворачиваться в строки.

Для этого используются свойства по умолчанию. Как вы успели заметить, литералы сворачиваются в их значения (свойство value), обычные объекты - в их имена (name), а свойства системных типов – в идентификаторы (id). Именно эти свойства и показываются нам в случаях, когда мы запрашиваем объекты с помощью null и []

Как лучше запрашивать объекты

Мы перечислили пять способов запроса объектов и соответствующие синтаксические конструкции, которые следует подставлять вместо искомых объектов

Значение Смысл
"свойство" : null
запрашивается значение свойства в виде одной строка. В качетсве этой строки будет выдано значение default-свойства объекта: value (для литералов) или name (для объектов). Если значением свойства является массив, выдается ошибка!
"свойство" : []
запрашивается массив строк. Результатом может быть пустой, массив, массив с одним значением или массив с несколькими значениями
"свойство" : {}
запрашивается краткая информация об объекте. Для обычных объектов выдается их имя, идентификатор и тип
"свойство" : [{}]
запрашивается массив объектов в кратком виде. Работает аналогично {}, но для массивов
"свойство" : {вложенный запрос}
у объекта-значения свойства спрашивается все, что указано в запросе
"свойство" : [{вложенный запрос}]
вложенный запрос относится ко всем объектам в массиве значений свойств. Действует аналогично предыдущему для массивов.

В связи с тем, что никто не любит ошибки в запросах, лучше всего всегда запрашивать значения свойств как массивы. Также советуем разработчикам быть осторожными с массивами вложенных запросов и глубиной вложенности последних - для больших массивов объектов обработка таких запросов может занять продолжительное время.

Wildcards

Операторы и директивы

Любой запрос в MQL по своей сути является конъюнкцией ограничений на выдаваемый результат. Метафорически, до сих пор мы задавали Freebase вопросы следующего типа:

Выдай мне все объекты у которых свойство1=значение1  И 
                                    свойство2=массив2     И 
                                    свойство3={объект3, в котором СВОЙСТВО4=значение4}
                                    свойство5=null

Что если нас не устраивает связка И между этими запросами? Порой хочется написать запрос, в котором вместо И будет ИЛИ и НЕ. Для этого у нас в распоряжении имеются операторы.

Как быть, если хочется, чтобы Freebase восприимала часть моих ограничений, не как ограничения, а как пожелания? Что-то вроде "верни мне значение для свойства5, если оно существует. Но если у каких-то объектов нет свойства5, мне все равно интересно узнать о них все остальные вещи, указанные в запросе." В этом случае мы прибегаем к необязательным (опциональным) совпадениями.

Почему до сих пор мы видели только ограничения на равенство какому-то значению? Есть же еще и другие операторы: больше, меньше, не равно. А если значения строковые, было бы приятно сравнивать их чуть более умными алгоритмами, чем просто проверкой посимвольной эквивалентности. Все это возможно с операторами MQL, которые присоединяются прямо к именам свойств.

Количество результатов часто хочется ограничить и отсортировать. И наконец, нас не всегда интересуют собственно объекты - иногда хочется просто посчитать их количество. Для этого созданы директивы MQL.

Операторы MQL

На самом деле, после того, как мы разобрались с базовыми понятиями MQL и поняли общую идею того, как строить запросы, остальное является делом техники. В этой главе мы рассмотрим операторы MQL.


Операторы сравнения

Оператор ИЛИ

Оператор НЕ

Директивы MQL

Опциональные совпадения

Запрещенные совпадения

Подсчет количества результатов

Лимитирование, сортировка

Индексы и упорядоченные коллекции

  1. http://wiki.freebase.com/wiki/Freebase_data - статистика данных во Freebase
  2. http://www.freebase.com/queryeditor/about - краткое описание возможностей MQL-редактора
Источник — «http://test.wikivote.ru/index.php/MQL»
Личные инструменты
Пространства имён
Варианты
Действия
Навигация
Инструменты