Семантическая сеть. Часть 3

March 17, 2008

Я продолжаю рассказ о технологиях, которые составляют ядро Семантической Паутины. В прошлый раз я завершил краткое введение в RDF и рассказал о проекте Dublin core. Сегодня фокус внимания будет посвящен FOAF, XFN, openid, социальным сетям.

Люди – социальные существа: любят жить в коллективе, общаться, распространять сплетни и обсуждать других. К этому можно относиться по разному: осуждать бездельников, которые тратят свое или (что еще ужаснее) время вашего работодателя на бесконечных “одноклассниках” или “в-контактах”. Можно восхищаться новыми возможностями открытого обсуждения и обмена опытом. А можно просто делать деньги. Не секрет, что львиная доля стоимости любого сайта “социальной сети” – это база его участников, и чем она больше, чем полнее и тем за большие деньги ее можно продать поставщикам рекламы. Действительно, любой рекламодатель отдаст свою правую руку за возможность получить миллионы почтовых адресов или личных сведений о своих будущих клиентах, да еще отсортированные по интересам, возрасту, кругу общения. В нашей стране эти процессы, мягко говоря, еще не выражены, но рано или поздно нам придется последовать примеру России, не говоря уже о дальнем зарубежье.

В начале 2007 года мне попался на глаза прогноз Ричарда Мак-Мануса (очень толковый блоггер http://www.readwriteweb.com/, есть переводы его постов и на русском языке). Он рассказывал о том, что прошедший год (2006) был годом пика социальных сетей, был временем, когда крупные компании выкладывали астрономические суммы за акции подобных “виртуальных компаний”. Писал о том, что в следующем году люди устанут от десятков сетей, стоимость акций должна упасть, в худшем случае фокус внимания перейдет от сетей общего назначения к специализированным сетям (для автолюбителей, для любителей хомячков и т.д.). В конце концов, социальные сети должны приносить пользу в реальном мире, а не отнимать дорогое время на болтовню (как я понимаю людей, которые во время работы отключают телефоны, icq и прочие цветки на могиле рабочего времени). В мире социальных сетей идет постоянный процесс “перемешивания”. Предположим, что вы зарегистрировались на некотором сайте, проводили там время, писали сообщения, завели круг друзей (точнее “виртуальных знакомых”), затем случилось страшное: “поменялась политика партии”, сервера стали “глючить” или просто надоело. Вы уходите на другой сайт (другую социальную сеть) и пытаетесь перетянуть за собой знакомых. Естественно, что часть людей не пойдет за вами, а останется на старом сервере – значит, сеть становится более раздробленной, затраты времени на поддержание “активной жизни” на нескольких сайтах становятся все более значительными. Выходом из сложившейся проблемы могут быть только … Нет, не построить мега-сеть, которая объединит все сети и станет сетью сетей, и придет Большой Брат (посвящается “1984” Оруэлла). Выход более простой и одновременно очень не приятный для компаний владельцев сетей-миллионников – согласовать и реализовать механизмы для переноса данных между сетями, создать средства для связывания десятков разрозненных учетных записей, сведений в блогах (как автономных, так и блого-платформах, вроде blogger, livejournal). Почему это плохо для владельцев крупных сетей? Повышение мобильности клиентов и возможность “за пару кликов мышью” перенести все свои персональные сведения и круг знакомств с одной сети в другую может за пару недель сделать из вчерашнего лидера рынка “голого короля”. Не зря же, в популярных российских социальных сетях “сами знаете, про кого я говорю” нет поддержки RSS и микроформатов. С другой стороны, альтернативы уже нет: компании-новички, желающие выйти на рынок социальных сетей и откусить свой кусочек пирога, должны предложить подобную функциональность, иначе им никогда не набрать приемлемой “начальной массы”, а значит не привлечь инвестиций и не продать рекламу. А, учитывая, что за их спиной маячит Его Величество google (я говорю про выступление в первых числах февраля этого года Brad-а Fitzpatrick-а, основателя ЖивогоЖурнала, работающего сейчас в google на проектом SocialGraph API), то пришло время менять подход к бизнесу. Скользким моментом во всех этих новомодных технологиях остается вопрос “доверия” и “идентификации людей”, также у каждого человека есть множество интересов или “ролей”, которые он играет на разных сайтах или сообществах и смешивать эти понятия в Супер-Граф он не хочет. Вопросов пока больше чем ответов, с другой стороны нас никто никуда не гонит и можно наблюдать со стороны за приключениями храброго Brad-а Fitzpatrick-а. На этом я закончу затянувшееся вступление и перейду к “немного попрограммировать”.

FOAF - это онтология (словарь терминов), в рамках которых мы можем описывать понятным для компьютера образом сведения о себе, о своих друзьях и отношениях между ними. Далее я привожу пример простейшего RDF файла (FOAF – расширением над RDF), в нем указаны сведения о некоторой персоне, адресе персональной страницы и адресе электронной почты.
  1. <rdf:RDF
  2.   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  3.   xmlns:foaf="http://xmlns.com/foaf/0.1/"
  4.   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  5.  <foaf:Person>
  6.   <foaf:name>Вася Тапкин</foaf:name>
  7.   <foaf:mbox rdf:resource="mailto:vasyano@site.ru" />
  8.   <foaf:homepage rdf:resource="http://www.tapkin.com/" />
  9.   <foaf:nick>tapkin</foaf:nick>
  10.  </foaf:Person>
  11. </rdf:RDF>
В начале файла я подключаю пространства имен rdf, rdfs, и виновника сегодняшнего материала foaf. Теперь я могу использовать foaf теги, описанные в спецификации (http://xmlns.com/foaf/spec/). Эта спецификация достаточно велика (более 60 терминов), но не все теги вам будут нужны (часть из них описывает сведения о том, в какой организации вы состоите, какие проекты ведете, где учились, дате рождения и т.д.). Все же наиболее ценные теги это: title, name, surname, family_name, firstName, nick - так мы укажем сведения о вашем имени. Если же вы желаете указать язык, на котором это имя записано, то используйте атрибут lang:
  1. <foaf:name xml:lang="ru">Василий Тапкин</foaf:name>
Теперь перейдем к вашему сетевому представительству. Мы можем указать теги для email (mbox). Однако, в случае, если вы не хотите явно указывать mbox (из-за спама), то более полезным будет тег mbox_sha1sum. К адресу почты применяется алгоритм хеширования SHA1.
  1. <foaf:mbox_sha1sum>5dff4261fb72b5a6eacbf94a9faddfba2518ba25</foaf:mbox_sha1sum>
Так как задача обратного преобразования SHA1 кодов не реализуема, то спам-роботы не получат ваши личные сведения, зато SHA1 код будет уникальным сетевым идентификатором в случае, если у вас нет сайта или icq-аккаунта. Для создания SHA1 кода можно воспользоваться одним из множества online-генераторов (например, http://xml.mfd-consult.dk/foaf/sha1ify/). Для организаций или сообществ имеющих представительство в реальном мире может быть полезен тег foaf:phone. Каждая сущность в FOAF-файле может иметь картинку логотипа, для этого используйте тег foaf:logo. Естественно, что картинок может быть много и они могут участвовать в отношениях, например, если вы хотите опубликовать отчет о прошедшей вечеринке. Так что рассмотрим средства вставки в FOAF-файлы изображений подробнее. В простейшем случае вы говорите: “вот моя фотография”:
  1. <foaf:depiction rdf:resource="http://fotka.ru/vasya.jpg" />
Тег depiction говорит, что на этой картинке отображена некоторая персона (внутрь тега Person которой и вложен тег depiction). А как быть, если мы хотим указать, что некоторая фотография содержит информацию о нескольких людях, плюс хотим добавить комментарий к ней, например, “Я и Ленка отдыхаем на Канарах”?
  1. <foaf:Person> 
  2.   <foaf:name>Вася Тапкин</foaf:name> 
  3.   <foaf:depiction> 
  4.    <foaf:Image rdf:about="http://fotki.ru/kanary.jpg"> 
  5.      <dc:title>То как Вася с Ленкой отдыхают на Канарах</dc:title>
  6.      <foaf:depicts>
  7.         <foaf:Person>
  8.            <foaf:name>Ленка</foaf:name>
  9.         </foaf:Person>
  10.      </foaf:depicts> 
  11.    </foaf:Image> 
  12.   </foaf:depiction> 
  13. </foaf:Person>
Если у вас есть собственный сайт или страничка на корпоративном сайт, то вы можете указать эту информацию с помощью тегов: homepage, weblog, workInfoHomepage, workplaceHomepage (и даже сайт школы, где вы учились), например:
  1. <foaf:weblog rdf:resource="http://my-personal-page.com/blog"/>
  2. <foaf:homepage rdf:resource="http://my-personal-page.com/vasya"/>
  3. <foaf:workplaceHomepage rdf:resource="http://fabrika.com"/>
  4. <foaf:workInfoHomepage rdf:resource="http://fabrika.com/director"/>
  5. <foaf:schoolHomepage rdf:resource="http://school_num_1.com"/>
Разница между workplaceHomepage и workInfoHomepage довольно скользкая, но считайте, что workInfoHomepage должна описывать работу которую вы делает для этой организации, а тег workplaceHomepage описывает саму организацию. В любом случае вы можете указать не просто адрес-идентификатор сайта, но и информацию о нем:
  1. <foaf:page>
  2.  <foaf:Document rdf:about="http://blackzorro.livejournal.com/profile">
  3.   <dc:title>LiveJournal.com Profile</dc:title>
  4.   <dc:description>Full LiveJournal.com.</dc:description>
  5.  </foaf:Document>
  6. </foaf:page>
Обратите внимание на использование тегов dc:title, dc:description. В прошлой статье я рассказывал о Dublin Core (DC), и теги title, description взяты из грамматики DC. Вот еще один пример перемешивания грамматик. Для вашей идентификации может быть использованы также и учетные данные в какой-либо из служб мгновенного обмена сообщениями: icq, jabber … Для этого используются теги с говорящими именами: icqChatID, msnChatID, aimChatID, jabberID, yahooChatID. В случае, если у вас еще есть учетные записи (ведь, действительно, нельзя создать термины для абсолютно всех сайтов и служб, к тому же их перечень постоянно изменяется). В этом случае вам помогут такие теги:
  1. <foaf:holdsAccount> 
  2.  <foaf:OnlineAccount>
  3.     <foaf:accountServiceHomepage rdf:resource="http://www.facebook.com/" />
  4.     <foaf:accountName>УЧЕТНАЯ_ЗАПИСЬ</foaf:accountName>
  5.  </foaf:OnlineAccount>
  6. </foaf:holdsAccount>
Для того чтобы все множество учетных записей хоть как-то классифицировать были введены типы: OnlineEcommerceAccount, OnlineGamingAccount, OnlineChatAccount. Это, соответственно, учетные записи для сайтов подобных amazon, ebay, затем игровые сайты, и наконец, учетные записи чатов, службах мгновенного обмена сообщениями.
  1. <foaf:holdsAccount> 
  2.     <foaf:OnlineAccount>
  3.        <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/OnlineChatAccount"/>
  4.        <foaf:accountServiceHomepage rdf:resource="http://chat.ru"/>
  5.        <foaf:accountName>tapkin</foaf:accountName>
  6.     </foaf:OnlineAccount>  
  7.   </foaf:holdsAccount>
FOAF файлы не обязательно писать ручками в блокноте: сейчас на рынке достаточно программ, которые представляют вам возможность ввести сведения об себе в некоторую форму, а затем автоматически сгенерируют foaf-файл, например, http://www.ldodds.com/foaf/foaf-a-matic. Это html-страница с формой, заполнив которую (поля имя, email, список друзей) вы получите xml-файл с foaf-профилем. Автор этой программки Leigh Dodds разработал еще одну разновидность foaf-генератора, но в виде java-приложения (http://www.ldodds.com/wordtin/Wiki.jsp?page=FOAFaMaticMark2). В крайнем случае, если у вас есть аккаунт на ЖивомЖурнале, то вы можете загрузить FOAF-файл со своими сведениями. Теми, которые вы указали при регистрации), а также список ваших друзей и статистику выполненных постов (правда здесь используется не FOAF грамматика, а схема “xmlns:ya="http://blogs.yandex.ru/schema/foaf/"). Еще раз повторю, что сила Семантической Паутины в способности смешивать в единое целое разные грамматики. Итак, если у вас есть учетная запись на ЖивомЖурнале, то FOAF страница будет иметь такой адрес http://МОЕ-ИМЯ.livejournal.com/data/foaf. Еще примером смешивания будет тег foaf:based_near, его назначение указать ваше основное местоположение. И как вы думаете, мы будем указывать значение для этого свойства? Что-то вроде, “на деревню дедушке”? Нам поможет еще одна грамматика http://esw.w3.org/topic/GeoRDF. Ее назначение запись географических координат в виде долгота/широта, например, так:
  1. <foaf:based_near>
  2.  <geo:Point geo:lat="17.5" geo:long="22.5"/>
  3. </foaf:based_near>
Теперь перейдем к главной функции FOAF – после создания списка персон в FOAF файле мы можем указать то, что они вложены в некоторые группы и определить отношение “дружбы” между персонами. Группа, равно как и Person, являются разновидностью некоторого “абстрактного агента”. В стандарте FOAF есть понятие агента как базового типа данных для “способных функционировать” сущностей. От этого типа данных производны Person (отдельные личности), Group (под группами понимаются достаточно широкие образования: формальные и неформальные группы, временные и длительные). Третьим видом Agent-ов являются организации (Organization). Возможно, все сказанное выше покажется очевидным, но внимание на этом я все же акцентирую, т.к. этот подход дает нам возможность комбинировать теги, также ряд свойств (foaf:homepage, foaf:name) совпадают и для группы и для отдельной персоны.
  1. <foaf:Group>
  2.  <foaf:name>Любители хомячков</foaf:name>
  3.  <foaf:member>
  4.   <foaf:Person> 
  5.        <foaf:name>Вася Тапкин</foaf:name>
  6.        <foaf:homepage rdf:resource="http://tapkin.ru"/> 
  7.   </foaf:Person> 
  8.   <foaf:Person>  
  9.        <foaf:name>Петя Пупкин</foaf:name>
  10.        <foaf:homepage rdf:resource="http://pupkin.ru"/>
  11.    </foaf:Person>
  12.  </foaf:member>
  13. </foaf:Group>
Пример показанный выше поднимает один важный вопрос: как быть, если один человек входит в состав нескольких групп? Не будем же мы дублировать описания Person для каждой из групп? В RDF (заметьте, не в FOAF) есть способ пометить некоторый узел с помощью идентификатора, затем, когда вы хотите сослаться на этот узел, достаточно указать его идентификатор, например, так:
  1. <foaf:Person rdf:nodeID="tapkin">
  2.   <!-- информация о Тапкине -->
  3. </foaf:Person>
  4. <foaf:Group>
  5.  <!-- теперь сошлемся на ранее созданный узел -->
  6.  <foaf:member rdf:nodeID="tapkin"/>
  7. </foaf:Group>
Когда мы проектируем группу и указываем, кто входит в ее состав, нам нужен механизм указания дополнительных сведений о персоне. Согласитесь, что наш FOAF документ не может быть единственными источником сведений о человеке, у него может быть собственный FOAF-файл. Давайте укажем с помощью seeAlso путь к нему:
  1. <foaf:Person rdf:nodeID="tapkin">
  2.  <foaf:name>Тапкин</foaf:name>
  3.  <rdfs:seeAlso rdf:resource="http://site.ru/tapkin.rdf"/>
  4. </foaf:Person>
Такой механизм еще раз акцентирует внимание на том, что информация о профиле человека может быть распределена по различным хранилищам, нескольким социальным сетям. Теперь перейдем к “друзьям”. Почему я заключил слово друзья в кавычки? В реальной жизни термин друг имеет совершенно отличное значение от того, который вкладывается а аббревиатуру FOAF (friend of a friend): есть друзья, приятели, знакомые, товарищи и множество оттенков и особенностей. В терминологии FOAF друг это тот, кого мы знаем, ни более. Если вам нужен способ указать на особые отношения (перечисленные выше) или, скажем, родственные связи, то нужны другие грамматики. Итак, используя тег foaf:knows, вы просто скажите что одна “foaf:Person” “foaf:knows” другую персону. За кадром остался вопрос о взаимности такого отношения.
  1. <foaf:Person rdf:nodeID="tapkin"> 
  2.    <foaf:name>Вася Тапкин</foaf:name>
  3. </foaf:Person>
  4. <foaf:Person>  
  5.   <foaf:name>Петя Пупкин</foaf:name>
  6.   <foaf:knows rdf:nodeID="tapkin"/>
  7.   <foaf:knows> 
  8.      <foaf:Person>
  9.         <foaf:name>Лена Кошкина</foaf:name> 
  10.      </foaf:Person> 
  11.   </foaf:knows>
  12. </foaf:Person>
Я, используя упомянутый ранее rdf атрибут “nodeID”, построил небольшую социальную сеть: в текущем RDF файле хранятся сведения о Пете Пупкине и его двух друзьях. Заметьте, что сведения о Лене Кошкиной задаются внутри тега knows, в то время как на Васю Тапкина идет ссылка с помощью nodeID.

Предположим, что вы заинтересовались FOAF и хотите внедрить эту информацию на свою персональную страницу. Начнем мы с того, что заявим свое авторство для некоторой страницы. Для этого вы может в FOAF файле перечислить адреса тех ресурсов, автором которых вы являетесь:
  1. <foaf:Person>
  2.   <foaf:mbox rdf:resource="mailto:tapkin@mail.ru" />
  3.   <foaf:made rdf:resource="http://mega-site.ru" />
  4.   <foaf:made rdf:resource="" />
  5. </foaf:Person>
Здесь указано, что некто Тапкин является разработчиком сайта mega-site.ru, а также создал, собственно, FOAF документ (на это указывает пустое значение атрибута rdf:resource). В FOAF предусмотрен также тег foaf:fundedBy, указывающий на вашу эксклюзивную роль в основании некоторого проекта. Однако (и это одна из тех вещей, которые мне страшно не нравятся) в стандарте FOAF хватает тегов, которые “возможно будут пересмотрены в будущем” (fundedBy как раз из их числа). Очевидно, что перечислять все созданные вами страницы в FOAF файле крайне неудобно, и гораздо лучше, если мы можем указать сведения в самом html-файле. Для этого в теге head вы добавляете тег link следующего вида:
  1. <link rel="meta" type="application/rdf+xml" title="FOAF" href="http://site.ru/myfoaf.rdf" />
Вот только момент: хоть все приведенные ранее примеры содержали информацию только об одном человеке, но в общем случае foaf-файл может хранить сведения о множестве людей, каждый из которых будет представлен тегом foaf:Person. Значит, нужен механизм указания кто из них я, кто написал этот сайт или эту страницу. Для этого в секции head страницы вы записываете ссылку на адрес почты некоей персоны из FOAF-файла (можно использовать и SHA1 версию почтового адреса).
  1. <meta name="foaf:maker" content="foaf:mbox mailto:tapkin@mail.ru " />
  2. <meta name="foaf:maker" content="foaf:mbox_sha1sum '5dff4261fb72b5a6eacbf94a9faddfba2518ba25' />
Если вы экспортируете новости своего сайта с помощью RSS, то внедрить туда FOAF-данные будет еще проще:
  1. <rss:channel rdf:about="http://mega-site.ru/feed">
  2.  <foaf:maker>  
  3.    <foaf:Person>
  4.       <foaf:mbox rdf:resource="mailto:tapkin@mail.ru" />
  5.     </foaf:Person> 
  6.  </foaf:maker>
  7. </rss:channel>
Возможно, сделать и наоборот: внедрить ссылку на созданный вами RSS-поток новостей в FOAF-файл.

В следующий раз я продолжу рассказ о технологиях Semantic Web и перейду к XFN, openid. Попробую создать небольшое php приложение “вытягивающее” описанные в FOAF данные. Еще мы “поиграем” со специальным языком запросов к RDF-документам SPARQL.