[PYTHON] Lassen Sie uns das Wissen über Wikidata mit Neo4j visualisieren

Dies ist der Artikel am 8. Tag des Adventskalenders 2019, NTT Docomo Service Innovation Department. Dieses Mal werde ich die Daten von ** Wikidata **, einer der strukturierten Wissensdatenbanken, mit ** Neo4j **, einer der Graph-DBs, visualisieren.

Was ist Graph DB?

Einfach ausgedrückt handelt es sich um eine Datenbank, die Diagrammstrukturen verarbeiten kann. Im Vergleich zur beliebten RDB handelt es sich um eine Datenbank, die für die Verarbeitung von ** Beziehungen ** zwischen Daten [^ 1] ausgelegt ist. Ein Diagramm ist übrigens kein Liniendiagramm oder Balkendiagramm, sondern eine Datenstruktur wie in der folgenden Abbildung dargestellt, die durch eine Reihe von Knoten (Kontaktpunkten) und Kanten (Zweigen) dargestellt wird (zitiert aus Wikipedia).

6n-graf.png

Ich weiß nicht, was es nützlich ist, diese Figur allein zu betrachten, aber die Diagrammstruktur ist sehr nützlich, um verschiedene Dinge in der realen Welt auszudrücken. Wenn Sie sich beispielsweise einen Bahnhof als Knoten und eine Eisenbahn als Kante vorstellen, können Sie eine Streckenkarte als Grafik ausdrücken. Wenn Sie sich eine Stadt als Knoten und eine Straße als Kante vorstellen, können Sie ein Transportproblem ausdrücken. Sie können SNS auch grafisch darstellen, indem Sie Konten als Knoten und Beziehungen zwischen Konten als Kanten betrachten. In Bezug auf die praktische Anwendung scheint es, dass die Kaufhistorie in einer grafischen Struktur ausgedrückt und für die Produktempfehlung verwendet werden kann [^ 2].

Monogoto, das ausgedrückt werden kann Knoten Kante
Straßenkarte Bahnhof Linie
Logistik Stadt Straße
SNS Konto Konto間の関係
Internes Personal Mitarbeiter Mitarbeiter同士の関係
Wikipedia Seite Seite間のリンク

In jüngster Zeit scheint die Aufmerksamkeit für die Grafikstruktur auch im Bereich der Sprachverarbeitung zuzunehmen. Beispielsweise wurde bei ACL, der internationalen Top-Konferenz zur Verarbeitung natürlicher Sprache, im vergangenen Jahr 3 GCN-bezogene Beiträge (Graph Convolutional Netowrk) eingereicht. In diesem Jahr ist die Zahl deutlich auf 11 gestiegen.

Verwenden wir diese Diagramm-DB, um die Beziehung zwischen bestimmten Fakten zu visualisieren.

Informationsextraktion aus Wikidata

Für die Visualisierung müssen Daten visualisiert werden, es ist jedoch schwierig, Daten manuell von Grund auf neu zu erstellen. Daher verwenden wir dieses Mal den Speicherauszug von ** Wikidata ** [^ 3], einer vorstrukturierten Wissensdatenbank, um die Daten zu erstellen, die in die Diagramm-DB importiert werden sollen. "Strukturiert" bedeutet "einfach mit einem Computer zu handhaben".

Wikidata ist eine kollaborative Wissensbasis und eines der gleichen Wikimedia-Projekte wie Wikipedia. In Wikidata zum Beispiel wird "Wissen", dass "John Lennons Nationalität das Vereinigte Königreich ist", in Drillingen wie (John Lennon, Nationalität, Vereinigtes Königreich) ausgedrückt. Diese Form von (Entität 1, Eigenschaft, Entität 2) wird als ** Beziehungsdreifach ** bezeichnet. Sie können sich die Entität hier als Titel einer Seite auf Wikipedia vorstellen. Jede Entität hat eine Wikidata-spezifische Kennung, die mit "Q" beginnt (z. B. bezieht sich Q5 auf "Mensch"). Ebenso verfügt die Eigenschaft über eine Wikidata-spezifische Kennung, die mit "P" beginnt.

Alle Wikidata-Daten werden ungefähr jeden Mittwoch im JSON-Format ausgegeben. Verwenden Sie diese Daten also als Daten, die in die Diagramm-DB importiert werden sollen. Laden Sie entweder latest-all.json.bz2 oder latest-all.json.gz von [hier] herunter (https://dumps.wikimedia.org/wikidatawiki/entities/). Weitere Informationen zur Struktur des JSON finden Sie unter hier.

Im Moment können Sie das Python-Skript wie unten gezeigt ausführen, um Entitäts- und Eigenschaftsinformationen oder relationale Tripel aus dem Speicherauszug zu extrahieren (beachten Sie, dass dies zeitaufwändig und speicherintensiv sein kann).

Beispielskript
#!/usr/bin/env python
# coding: utf-8

import bz2
import json
import codecs

triples = []
qs = []
with bz2.BZ2File('latest-all.json.bz2', 'r') as rf, \
     codecs.open('rdf.tsv', 'w', 'utf-8') as rdff, \
     codecs.open('q_id.tsv', 'w', 'utf-8') as qf:
    next(rf)  #Überspringen Sie die erste Zeile
    for i, line in enumerate(rf, 1):
        try:
            line = json.loads(line[:-2])
        except json.decoder.JSONDecodeError:
            print(i)
            rdff.write('\n'.join(['\t'.join(x) for x in triples]) + '\n')
            qf.write('\n'.join(['\t'.join(x) for x in qs]) + '\n')
            triples = []
            qs = []
            continue

        try:
            ett_id = line['id']
        except KeyError:
            ett_id = None
        try:
            ett_name = line['labels']['ja']['value']
        except KeyError:
            ett_name = None

        if ett_id is not None and ett_name is not None:
            qs.append((ett_id, ett_name))
            triple = []
            for _, props in line['claims'].items():
                for prop in props:
                    p_id = prop['mainsnak']['property']
                    try:
                        id_ = prop['mainsnak']['datavalue']['value']['id']
                    except Exception as e:
                        # print(ett_id, p_id, e)
                        continue
                    triple.append((ett_id, p_id, id_))
            triples.extend(triple)
            triple = []

        if i % 10000000 == 0:
            print(i)
            rdff.write('\n'.join(['\t'.join(x) for x in triples]) + '\n')
            qf.write('\n'.join(['\t'.join(x) for x in qs]) + '\n')
    rdff.write('\n'.join(['\t'.join(x) for x in triples]) + '\n')
    qf.write('\n'.join(['\t'.join(x) for x in qs]) + '\n')

q_id.tsv ist eine durch Tabulatoren getrennte Datei, wie in der folgenden Tabelle gezeigt (diese Datei enthält nicht nur Q ID, sondern auch P ID).

Q ID Entitätsname
Q31 Belgien
Q8 Glück
Q23 George Washington
Q24 Jack Bauer
Q42 Douglas Adams

Außerdem sind "rdf.tsv" tabulatorgetrennte Daten, wie in der folgenden Tabelle gezeigt.

Entität 1 Eigentum Entität 2
Q31 P1344 Q1088364
Q31 P1151 Q3247091
Q31 P1546 Q1308013
Q31 P5125 Q7112200
Q31 P38 Q4916

Kombinieren Sie die beiden oben genannten Dateien, um zwei Dateitypen zu erstellen. Fügen Sie zunächst einen Header zu "q_id.tsv" hinzu, um die durch Tabulatoren getrennten Daten "node.tsv" zu erstellen und zu speichern, wie in der folgenden Tabelle gezeigt (die dritte Spalte ": LABEL" kann vorhanden sein oder nicht). Es gibt so etwas nicht, also können Sie den Dateinamen einfach umbenennen.

id:ID name :LABEL
Q31 Belgien Entity
Q8 Glück Entity
Q23 George Washington Entity
Q24 Jack Bauer Entity
Q42 Douglas Adams Entity

Gleichzeitig werden die Eigenschaften zwischen Entitäten auch als tabulatorgetrennte Daten "ratios.tsv" gespeichert, wie in der folgenden Tabelle gezeigt. Fügen Sie einfach einen Header zu "rdf.tsv" hinzu und ersetzen Sie ": TYPE" in der zweiten Spalte durch eine Zeichenfolge aus "P000", indem Sie auf "q_id.tsv" verweisen (tatsächlich besteht keine Notwendigkeit, dies ebenfalls zu ersetzen. Es gibt so etwas nicht, also können Sie einfach den Dateinamen umbenennen.

:START_ID :TYPE :END_ID
Q23 Ehepartner Q191789
Q23 Vater Q768342
Q23 Mutter Q458119
Q23 Brüder und Schwestern Q850421
Q23 Brüder und Schwestern Q7412891

Es gibt verschiedene Arten von Eigenschaften wie "Nationalität", "Ehepartner", "Geburtsort" und "Geburtstag", aber es gibt zu viele, wie sie sind, also in dieser Visualisierung zwischen Menschen Ich habe mich auf die Eigenschaften beschränkt, die definiert werden können. Zum Beispiel "Verwandte", "Väter", "Mütter", "Meister" und "Jünger". Außerdem sind die Entitäten auf solche mit japanischen Namen beschränkt.

Versuchen Sie es mit Neo4j

Es gibt verschiedene Arten von Graph-DBs, aber hier werden wir Neo4j [^ 4] vorstellen, das relativ beliebt ist. Neben Neo4j finde ich Amazon Neptune berühmt (der Name ist cool) [^ 5].

Installation

Für macOS wird empfohlen, Homebrew zu installieren.

$ brew cask install homebrew/cask-versions/adoptopenjdk8  #Wenn Java nicht enthalten ist
$ brew install neo4j

Wenn die Version von "Java" anders ist

neo4j: Java 1.8 is required to install this formula.
Install AdoptOpenJDK 8 with Homebrew Cask:
  brew cask install homebrew/cask-versions/adoptopenjdk8
Error: An unsatisfied requirement failed this build.

Bitte beachten Sie, dass Sie wütend werden.

Wenn Sie "$ which neo4j" eingeben und die Meldung "/ usr / local / bin / neo4j" angezeigt wird, ist die Installation abgeschlossen.

Daten importieren

Importieren Sie die zuvor erstellten node.tsv und ratios.tsv in Neo4j. Drücken Sie den folgenden Befehl, um die Daten zu importieren.

$ neo4j-admin import --nodes ./Downloads/nodes.tsv --relationships ./Downloads/relationships.tsv --delimiter="\t"

Wenn der Import erfolgreich ist

IMPORT DONE in 9s 735ms.
Imported:
  2269484 nodes
  201763 relationships
  6808452 properties
Peak memory usage: 1.05 GB

Wird angezeigt.

Verwenden Sie die folgenden Befehle, um den Neo4j-Server zu starten und zu stoppen.

$ neo4j start  #Beim Starten des Servers
$ neo4j stop  #Beim Stoppen des Servers

Versuchen Sie nach dem Starten des Servers, auf "http: // localhost: 7474" zuzugreifen. Wenn Sie zum ersten Mal darauf zugreifen, werden Sie aufgefordert, sich anzumelden. Geben Sie daher "neo4j" in den Benutzernamen bzw. das Kennwort ein. Danach werden Sie aufgefordert, das Passwort zu ändern. Ändern Sie es daher in ein beliebiges Passwort.

Daten mit Cypher verarbeiten

Jetzt bist du bereit. Verwenden wir sofort Neo4j. Neo4j verwendet eine SQL-ähnliche Sprache namens ** Cypher ** als Abfrage (Cypher wird im Folgenden als CQL bezeichnet). Bitte beachten Sie, dass dieser Artikel keine detaillierte Erklärung von CQL enthält.

Der 8. Dezember, wenn dieser Artikel veröffentlicht wird, ist John Lennons Sterbedatum. Nehmen wir also John Lennon als Thema. Nebenbei mag ich "Jealous Guy" am meisten.

N-Hop-Suche

Wenn Sie beispielsweise die mit "John Lennon" verknüpfte Entität anzeigen möchten, geben Sie die folgende CQL aus. Diese CQL gibt alle Entitätsknoten vom "John Lennon" -Knoten an 3-Hop zurück.

match p=((:Entity{name:"John Lennon"})-[*1..3]-()) return p

graph-6.png

Es ist etwas verwirrend, aber der "John ..." - Knoten unten links in der Mitte ist der "John Lennon" -Knoten. Zum Beispiel von "John Lennon" aufwärts "Ono Yoko" (1) → "Zenzaburo Yasuda" (2) → "Kataoka Jinzaemon" (3) und die Beziehung erstreckt sich auf 3-Hop. Ich werde. Der untere rechte Klumpen ist der bekannte Paul McCartney und seine Familie.

Leider gibt es in dieser Grafik keine Namen von Ringo Star oder George Harrison, die Mitglieder der Beatles waren.

Kürzeste Routensuche

Neo4j kann nach der kürzesten Route suchen, was eines der Hauptmerkmale ist.

Versuchen wir, den kürzesten Weg zwischen "Natsume Soseki" und "Mori Kogai", den literarischen Meistern der Meiji-Ära, zu finden. Der 8. Dezember hat nichts damit zu tun. Nebenbei mag ich "Keibi-Kusa" am meisten.

Stellen Sie eine CQL aus, die der folgenden ähnelt: Schließen Sie einfach das CQL "Alle Knoten zwischen" Natsume Soseki "und" Mori Kogai "" mit "kürzestem Pfad" ein.

match p=shortestpath((:Entity{name:"Natsume Soseki"})-[*]-(:Entity{name:"Mori Kogai"})) return p

graph-5.png

"John ..." an der Spitze ist nicht John Lennon, sondern "John Manjiro".

Die beiden lebten zur gleichen Zeit, aber basierend auf dem Wissen von Wikidata ist die Beziehung überraschend weit entfernt. Nach historischen Fakten scheint es keine Interaktion zu geben, die ein Austausch miteinander zu sein schien, da sie sich kannten.

Was ist dann der kürzeste Weg zwischen "John Lennon" und "Natsume Soseki", die nichts miteinander zu tun zu haben scheinen?

match p=shortestpath((:Entity{name:"Natsume Soseki"})-[*]-(:Entity{name:"John Lennon"})) return p

graph-4.png

Nachdem er von "Natsume Soseki" zu "Ryunosuke Akutagawa" und "Samuel Beckett" (Autor des Dramas "Waiting for Godo") gearbeitet hatte, war er berühmt für "Bob Dylan" ("Like a Rolling Stone" und gewann den Nobelpreis für Literatur. ), Nachdem Sie die Brücke zwischen Literatur und Musik passiert haben, scheinen Sie "Jimi Hendrix", "Prince", "Shakira" und "John Lennon" zu erreichen. Um ehrlich zu sein, kann ich das Gefühl nicht leugnen, ein wenig abrupt zu sein und einen Umweg zu machen [^ 6].

Wikidata sind ziemlich große strukturierte Daten, aber sie scheinen für die sofortige Verwendung als Wissensbasis etwas unzureichend zu sein. Sie müssen Ihre Wissensbasis beispielsweise mit ** Beziehungsextraktion ** erweitern. Die Beziehungsextraktion ist eine Technik zum Extrahieren des Beziehungs-Tripels (Natsume Soseki, Autor, "Botsuchiyan") aus dem Satz "Natsume Soseki, der Autor von" Botsuchiyan "."

Zusammenfassung

Ich habe versucht, das Wissen über Wikidata mit Neo4j zu visualisieren. Das mit Neo4j gezeichnete Diagramm kann im Browser wellig verschoben werden und macht Spaß. Üben und berühren Sie es daher selbst.

[^ 2]: https://ja.wikipedia.org/wiki/ Ich bin mit der Graphentheorie vertraut

[^ 5]: Herr Hayashi hat letztes Jahr einen Artikel in unserem Adventskalender geschrieben → https://qiita.com/dcm_hayashi/items/9b2536b6fbffa0118fad

[^ 6]: "Nakamura Yoshiko", der beste Freund von "Natsume Soseki" aus der Highschool-Zeit, ist als einer der Vertrauten von "Goto Shinpei" bekannt, der als Präsident Mantetsu und Bürgermeister von Tokio gedient hat. Danach war es "Zenjiro Yasuda", der dem von Fuji vorgeschlagenen Stadtplan zustimmte (übrigens wurde zu dieser Zeit die öffentliche Halle von Hibiya gebaut). Und wenn Sie Yasudas Urenkel folgen, wie Sie "Ono Yoko" und ihren Ehepartner als "John Lennon" kennen, kann dies viel kürzer sein als das Ergebnis von Wikidata.

Recommended Posts

Lassen Sie uns das Wissen über Wikidata mit Neo4j visualisieren
Mit Pandas schnell visualisieren
Visualisieren Sie Ansprüche mit AI
Sandkasten mit neo4j Teil 10
Lassen Sie uns 2ch Thread mit WordCloud-Scraping- visualisieren
Visualisieren Sie den Entscheidungsbaum mit einem Jupyter-Notizbuch
Visualisieren Sie Python-Paketabhängigkeiten mit graphviz