Вивчаємо граф-орієнтовану СУБД Neo4j на прикладі лексичної бази Wordnet

СУБД Neo4j — це NoSQL база даних, орієнтована на зберігання графів. Родзинкою продукту є декларативний мову запитів Cypher.

Cypher запозичив ключові слова типу WHERE, ORDER BY з SQL; синтаксис з таких різних мов як Python, Haskell, SPARQL; і в результаті з'явився мову, що дозволяє робити запити до графів у візуальній формі на зразок ASCII art. Наприклад, заголовок даної статті я би представив у вигляді графа (Neo4j) — [вивчаємо] -> (Wordnet). І це майже готовий запит до бази даних!

Джерело картинкиwww-rohan.sdsu.edu/~gawron/compling/course_core/assignments/lex_sem_assignment.htm


Для вивчення граф-орієнтованої бази даних потрібен якийсь граф. Це може бути соціальна мережа, дамп вікіпедії чи схема залізниць. Ми підемо простим шляхом і скористаємося величезним загальнодоступним графом лексичної бази Wordnet. Лінгвісти з Прінстона провели гігантську роботу по систематизації словникового запасу англійської мови, а ентузіасти перевели базу даних на багато мов, включаючи російську. Наприклад, у цій базі понад 80 тисяч іменників, пов'язаних між собою лексичними відносинами, такими як «синонім», «частина більшого», «матеріал» і т. п. Ця база є природним графом, і ми її імпортуємо в Neo4j.

Установка Neo4j
Процес установки для різних ОС описаний на сайт. Все описане тут платформно-незалежний, але для визначеності всі інструкції будуть для Debian/Ubuntu.

1. Додати репозиторій
wget -O - https://debian.neo4j.org/neotechnology.gpg.key | sudo apt-key add -
echo 'deb http://debian.neo4j.org/repo stable/' >/tmp/neo4j.list
sudo mv /tmp/neo4j.list /etc/apt/sources.list.d
sudo apt-get update

2. Встановити Neo4j (community edition)
sudo apt-get install neo4j

Ця команда встановить у вашу домашню директорію і запустить сервіс, який буде працювати від імені користувача neo4j.

3. Дозволити віддалений доступ
Якщо ви встановили Neo4j на свій комп'ютер, пропустіть цей крок. Якщо ж потрібен доступ до сервера з інших комп'ютерів в локальній мережі, відредагуйте файл /var/lib/neo4j/conf/neo4j-server.properties

Для доступу з будь-якого комп'ютера локальної мережі встановіть параметри:

org.neo4j.server.webserver.address=0.0.0.0
субд.security.auth_enabled=false

За замовчуванням використовується порт 7474, змінити порт можна, додавши рядок у той же файл:

org.neo4j.server.webserver.port=7474

Зверніть увагу, що ми не налаштували безпека СУБД! Більш докладно читайте інструкцію.

Перевірити установку можна, набравши в браузері адресу і порт сервера. Neo4j реалізує розкішну графічну консоль через браузер. Через цей же порт йдуть REST-запити до бази від клієнтського програмного забезпечення, яке ми встановимо на наступному кроці.

Установка клієнта (Python)
Для того, щоб імпортувати базу Wordnet в Neo4j, скористаємося скриптом на Пітоні.

1. Спочатку потрібно встановити бібліотеку py2neo
pip install py2neo

2. Скачайте з гитхаба мій скрипт
mkdir habrawordnet2neo4j
cd habrawordnet2neo4j
git clone https://github.com/sergey-zarealye-com/wordnet2neo4j.git

Скрипт навряд чи претендує на промислове якість коду, але якщо ви захочете поекспериментувати з Neo4j з Пітона, то перегляньте код, це допоможе вам швидше почати програмувати.

Отримання лексичної бази даних Wordnet
На сторінці Завантажити проекту Wordnet пропонується завантажити базу разом з програмним забезпеченням для її перегляду. Але ми хочемо використовувати для перегляду Neo4j! Тому досить завантажити тільки файли з даними:

Розпакуйте файли в доступне місце.

Імпорт даних в Neo4j
Лексичні дані в Wordnet лежать в файлах за частинами мови. Наприклад, іменники знаходяться у файлі data.noun; дієслова — data.verb; а з іншими частинами мови я і не пробував.

1. Імпорт іменників
Для імпорту іменників перейдіть в директорію, куди помістили мої скрипти (ми її назвали просто habrawordnet2neo4j) і виконайте команду в консолі:

python wordnet2neo4j.py -i rwn3/data.noun --neo4j http://127.0.0.1:7474 --nodelabel Ruswordnet --reltype Pointer --encoding cp1251 --limit 1000

Давайте розберемо параметри детальніше.

-i шлях до файлу даних Wordnet
--neo4j URL сервера бази даних Neo4j
--nodelabel Мітка вузлів, відповідних словами Wordnet
в створюваному графі (в Neo4j вузли графа забезпечують
текстовими мітками; це просто ідентифікатор)
--reltype Тип ребер графа, відповідних вказівниками Wordnet
(у Neo4j ребра графа можуть мати тип; це просто
ідентифікатор)
--encoding Кодування файлу даних; російськомовна база записана
в кодуванні cp1251; для англомовних файлів цей
параметр не потрібно вказувати
--limit Максимальна кількість оброблюваних рядків файла;
справа в тому, що мій скрипт працює досить повільно,
і щоб спробувати можна обмежити обсяг імпортованих
даних, наприклад першими 1000 рядками файлу; для імпорту
повного файлу цей параметр не потрібно вказувати,
і приготуйтеся почекати годину-півтора.

2. Імпорт дієслів
Для імпорту дієслів виконайте команду в консолі:

python wordnet2neo4j.py -i rwn3/data.verb --neo4j http://127.0.0.1:7474 --nodelabel Ruswordnet --reltype Pointer --encoding cp1251 --limit 1000

Імпортувати дієслова необов'язково, хоча деякі з них пов'язані з іменниками, і це цікаво повивчати.

3. Переконайтеся, що дані, імпортовані
Для цього відкрийте в браузері консоль Neo4j (введіть адресу і порт сервера СУБД) і введіть наступний запит:

MATCH (node)-[relation]-() RETURN node, relation LIMIT 100

Якщо отримали в екрані зображення графа, то все пройшло успішно.

Виконуємо прості запити
Всі подальші дії будемо виконувати в браузері, в консолі Neo4j. Я буду вважати, що в якості міток вузлів ви використовували Ruswordnet, а в якості типу ребер Pointer (як зазначено в попередньому розділі). І що ви імпортували саме російську базу Wordnet цілком.

1. Hello World
Як зазначено на сайті російської бази Wordnet, переведено близько половини смислових одиниць, що містять найбільш загальновживані слова. Тому спробуємо знайти у базі перше, що прийшло в голову:

MATCH (n:Ruswordnet {name: "выкапывание_трупа"}) RETURN n

Виконайте запит, переконайтеся, що це поняття знайдено, значить, на думку російських лінгвістів, воно входить у число найбільш общеупотребимых. Давайте розберемо цей простий запит.

Ключове слово MATCH означає приблизно те ж саме, що в SQL SELECT. Грубо кажучи, «знайти підходящі до шаблону елементи графа».

Круглими дужками позначаються вузли графа. Шаблон (n:Ruswordnet) означав би, що ми хочемо знайти всі вузли з міткою «Ruswordnet». Тут n — ідентифікатор, можна сказати «змінна».

Вузли графа (і ребра теж) можна постачати довільними атрибутами. Щоб знайти конкретний вузол, ми поставили в запиті умова атрибути форматі, схожому на JSON: {name: «выкапывание_трупа»}. Таким чином, фраза

MATCH (n:Ruswordnet {name: "выкапывание_трупа"})

означає, що з усього графа будуть обрані всі вузли з міткою Ruswordnet і атрибутом name рівним вказаною там поняттю.

Ключове слово RETURN говорить нам, які змінні нас цікавлять. В даному випадку ми просто хотіли побачити вузол (вузли), які відповідають заданим умовам, тому пишемо RETURN n. Важливо розуміти, що n — це колекція вузлів, що задовольняють запиту. Щоб переконатися в цьому, просто замініть поняття в запиті:

MATCH (n:Ruswordnet {name: "лев"}) RETURN n

Якщо ви імпортували базу Wordnet, ви побачите шість вузлів понять «лев». Давайте розберемося, чому.

2. Змінні = колекції
Виконаємо такий запит:

match (n:Ruswordnet {name: "лев"})--(m) return n,m

Тут ми поставили вже більш складний шаблон для пошуку. Ми хочемо знайти всі вузли(n), що відповідають поняттю «лев», а також всі вузли (m), пов'язані з левами. Зв'язок, тобто ребро графа позначається двома дефісами. Можна в явному вигляді вказувати напрям, який нас цікавить символом --> (це я і називав ASCII art).



Якщо у вас не відображаються імена смислових одиниць, натисніть на кнопку Ruswordnet(23) у лівому верхньому куті графа, і в рядку стану в нижній частині консолі виберіть «name» в полі Caption. Так буде наочніше.

Тепер ми зрозуміли, що лев це, виявляється не тільки болгарська валюта (bulgarian_money), копійкою для якої є стотинка, але і велика кішка, і сузір'я, астрологічний знак, і щось, пов'язане з гордістю.

3. Підключаємо ребра
В базі Wordnet ребра називаються вказівниками (Pointer), і використовується велика кількість лінгвістичних типів покажчиків. Вони позначаються символами, деякі з яких я приводжу в таблиці:
Символ Англійське найменування лінгвістичного відносини Лінгвістичне ставлення
! Antonym Антонім
@ Hypernym Узагальнення
@i Instance Hypernym Примірник узагальнення
~ Hyponym Уточнення
~i Instance Hyponym Примірник уточнення
#m Member holonym Поняття, що включає в себе це поняття
#s Substance holonym Речовина, з якої складається предмет
#p Part holonym Предмет, що включає в себе як частину даний предмет
%m Member meronym Частина більш загального поняття
%s Substance meronym З якої речовини складається предмет
%p Part meronym Частина предмету
= Attribute Атрибут
+ Derivationally related form Похідна форма
В процесі імпорту ми присвоїли ребрах графа атрибут pointer_symbol, і тепер можемо робити запити з урахуванням атрибутів ребер. Давайте розберемося, що таке узагальнення (hypernum):

MATCH (n:Ruswordnet {name: "лев"})-[p:Pointer {pointer_symbol: "@"}]->(m) 
RETURN n,m

Позначаються квадратними дужками специфікації ребер. В цьому запиті ми хочемо знайти ребра типу Pointer, атрибут яких pointer_symbol дорівнює «@» тобто символу узагальнення. До речі, протилежний узагальнення символ уточнення «~».



Тепер зрозуміло, що узагальнення для лева це кіт, а також людина. Звичайно, мова йде про різних смислових одиницях: лев (кіт) це один вузол графа, а лев (людина) — інший вузол, який відповідає знаку зодіаку. Лев (відомість) — це результат поганого перекладу на російську; мається на увазі лев (celebrity), тобто знаменитість, світський лев.

Давайте розберемося, що таке part holonym:

MATCH (n:Ruswordnet {name: "лев"})-[p:Pointer {pointer_symbol: "#p"}]->(m) 
RETURN n,m

А, тепер зрозуміло: лев входить в зодіаку в якості складової частини, значить зодіак є part holonym для лева.

З таблиці видно, що Wordnet містить багато цікавих відносин, наприклад, з якихось речовин, що зроблено. На жаль, немає інформації, що лев зроблений з м'яса, тому поставимо питання по іншому: знайти такі вузли графа, які пов'язані відношенням «з якої речовини зроблено».

MATCH (n)-[p:Pointer {pointer_symbol: "#s"}]->(m) 
RETURN n,m LIMIT 10

В цьому запиті ми не накладаємо ніяких умов на вузли (n) та (m). Ми тільки хочемо, щоб їх пов'язували ребра з атрибутом «#s». Зверніть увагу, з'явилося ключове слово LIMIT, знайоме нам з SQL. Якщо б його тут не було, сервер повернув би нам дуже багато результатів, і погано було б нашому браузеру.

В результаті запиту ми дізналися, що сигарети складаються з марихуани, а суп з волових хвостів — з волових хвостів.

4. Ланцюжки довільної довжини
У дитинстві всі грали в таку гру: перетворити муху в слона. Для цього потрібно було міняти по одній букві у слові, поки слово МУХА не перетворилося на слово СЛОН. Давайте дізнаємося в лексичному графі, пов'язані між собою ЛЕВ і ВІВЦЯ.
MATCH (n:Ruswordnet {name: "лев"})-[p:Pointer*1..3]-(m:Ruswordnet {name: "вівця"}) 
RETURN n,m,p

Конструкція [p:Pointer*1..3] говорить, що потрібно знайти ланцюжок ребер типу Pointer довжиною від одного до трьох, що зв'язує вузол «лев» з вузлом «вівця».



Це відрізняється від класичної дитячої гри, але теж цікаво: ВІВЦЯ — ПРОСТАК — ЛЮДИНА — ЛЕВ… це звучить гордо. До речі, можна спробувати знайти зв'язок між мухою і слоном, тільки трохи збільшити граничну довжину ланцюжка. Я використовував значення 6. До речі, не намагайтеся відразу поставити 100 — процес пошуку швидше за все зірветься т. к. кількість варіантів перебору шляхів у графі буде занадто велике. Отже, ось як пов'язані слон і муха лексично:



Думаю, на цьому етапі ви багато чого зрозуміли про базі даних Neo4j, і здатні самостійно відкрити багато цікавого у базі даних Wordnet, а може застосувати Neo4j в своїх проектах. Ми застосовуємо зв'язку Neo4j c Wordnet в системі пошуку по киноархивам. Якщо ви хочете займатися дослідженнями в області машинного навчання, запрошую на стажування або на постійну роботу в НИКФИ — науково-дослідний кинофотоинститут.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.