中国語学習×グラフデータベース(6) - ノードをまとめて作る

ついにNeo4jにデータを取り込む。

merge/merge_oneは使えるのか使えないのか

まずは簡単そうな短文を取り込む。すでに、sentence_listというリストに短文は取り込んであるので、こんな感じでOK。

for sentence in sentence_list:
    graph.merge_one("Sentence", "sentence", sentence)

ここで使っているmerge/merge_oneというのは、Select+Createみたいなイメージで、まず選択して対象がなければ登録するという感じで、なんとも便利そうではあるのだけれど、照合に使えるAttributeが1つだけというのが難点。ちなみにmerge_oneはuniqueness_constraintとセットで使えとドキュメントに書いてあったので従った次第である。上のケースでは良いが、単語とピンインが同一のモノという条件には対応していないのだ。

単語とカテゴリのNode登録とRelationship作成

引き続いて、単語(Word)の登録。こんなソースを書いて実行したんだけど、これは反省点も多し。

from datetime import datetime
start_time = datetime.now()
counter_a = 0
counter_c = 0
for word in word_list:
    counter_a += 1
    ws = list(graph.find("Word", "keyword", word['word']))
    found = False
    for w in ws:
        if w["pinyin"] == word['pinyin']:
            found = True
            break
    if found == True:
        new_word = w
    else:
        counter_c += 1
        new_word = Node("Word", keyword=word['word'], pinyin=word['pinyin'], pinyinf=word['pinyinf'], meaning=word['meaning'])
        graph.create(new_word)
    found = False
    if word.get('category'):
        cs = list(graph.find("Category", "category", word['category']))
        if len(cs) == 0:
            new_category = Node("Category", category=word['category'])
            graph.create(new_category)
        else:
            new_category = cs[0]
        word_is_categorized_as_category = Relationship(new_word, 'is_categorized_as', new_category)
        graph.create(word_is_categorized_as_category)
    
print("all count:{0}, created words:{1}".format(counter_a, counter_c))
endtime = datetime.now()
print ("It took {0} seconds to process".format{end_time - start_time})
all count:5809, created words:5806

とにかく時間がかかったのが1つと、今見返すとロジック的にイケてない。

単語(Word)Nodeは、keyword(単語そのもの)とpinyinの組み合わせでユニークにするするのだが、merge()と同じようにAttributeが1つしか指定できないfind()を使ったがために、keywordで選択した後にLoopして同じピンインのモノがなければ追加するというロジックになっている。これは、graph.cypher.execute()を使って、直接cypherクエリを呼び出すことで、1回で同じ単語かつピンインのモノがないかを確認するべきだったと反省。

後半のCategoryのところは、その単語にカテゴリが割当たっているかを確認する。重複がないのでfind()でもOKのはず。そこから、もし同じカテゴリの登録がなければ、新規に登録してから、さらにカテゴリと単語の間に"is_categorized_as"というRelationshipを作るところまでやっている。

いずれにせよ、単語数の2倍以上の回数のクエリが実行されているため、そのあたりの通信時間が処理時間に大きく影響を与えていると推測。

初めてのグラフ

f:id:deutschina:20160226162141p:plain

時間はかかったが、こんな感じで表示することが出来るようになった。成語にカテゴリされたキーワードが25個表示されている。(これはNeo4jから直接Cypherクエリを実行している)

(つづく)

グラフデータベース ―Neo4jによるグラフデータモデルとグラフデータベース入門

グラフデータベース ―Neo4jによるグラフデータモデルとグラフデータベース入門