Neo4jではてなブックマークグラフをつくってみた

最近Neo4jというデータベースに触れる機会がありました。

Neo4jはグラフ構造を扱えるデータベースシステムで、人間関係のネットワークやWebページ間のリンク関係などを扱うのに適しています。 グラフデータベースでは「友達の友達の友達」や「10以上リンクされているページ同士の相互リンク」といった情報を簡単に引き出すことができます。

これらをRDBMSで実現しようとすると何段ものJOINが必要となり、クエリが複雑になって計算量も増えてしまいがちです。 グラフデータベースを使えば、クエリを簡潔に保ち、計算量も抑えることができます。

今回は日頃から利用しているはてなブックマークのデータを使い、Neo4j上にはてブグラフを構築していろいろなクエリを試してみました。

はてなブックマークWebおよび公開APIから取得できるデータのみを使用しています。

グラフとは

ここでいう「グラフ」はExcelで描けるようなグラフとは異なり、「ノードとそれらの間の関係によって構成されるデータ構造」のことを意味します。

グラフ (データ構造) - Wikipedia

グラフ構造はとても興味深い性質をもっており、グラフ理論という数学の一分野で扱われます。

グラフ理論 - Wikipedia

はてブグラフとは

「ユーザがエントリをブックマークしている」ことは、「ユーザとエントリの間にブックマークという関係が存在する」こととみなせます。

f:id:yubessy:20150914135452p:plain

はてなブックマークでは、たくさんのユーザが各々たくさんのエントリをブックマークしているので、次のようなグラフが生じます。

f:id:yubessy:20150914135514p:plain

このようなグラフを はてブグラフ と呼ぶことにします。

はてブグラフを見れば、エントリの被ブックマーク数はもちろん、「どのユーザ同士が同じページをブックマークしているか」といったこともすぐにわかります。

ちなみに、このような2種類のノード(ユーザ・エントリ)をもち、なおかつ異なる種類のノード間にしか関係が存在しないようなグラフを「2部グラフ(bipartite graph)」と呼びます。 ユーザ間のお気に入り・入られや、エントリ間のリンクなどを考えない場合、はてブグラフは典型的な2部グラフとなります。

Neo4jのインストール

やっとNeo4jの登場です。

Neo4jはMySQL等と同様に、デーモンプロセスとして動作します。 インストールは、ダウンロード→展開→startで済みます。 Homebrewを使っていれば、以下を実行するだけでインストールと起動ができます。

$ brew install neo4j
$ neo4j start

Neo4jにはデフォルトでWebインタフェースが用意されており、プロセスを起動した状態で http://localhost:7474/ にアクセスすることですぐに利用できます。 データベースは基本的に1プロセスにつき1つです。RDBMSではないのでテーブルはなく、全てのオブジェクトはノードか関係のいずれかです。

Cypher: Neo4jのためのデータベース操作言語

RDBMSSQLを使うのと同様に、Neo4jではCypherというデータベース操作言語を使います。

以下のCypherプログラムは、ユーザとエントリのノードを作成し、その間にブックマーク関係を付与します。

CREATE
  (u:User {name: "yubessy"}),
  (e:Entry {url: "http://b.hatena.ne.jp/"}),
  (u)-[:BOOKMARK]->(e);

ノードは (<変数名>:<ラベル> {<属性名1>: <属性値1>, ...}) で表します。 ノードXからY間への関係は (<ノードX>)-[<変数名>:<ラベル> {<属性名1>: <属性値1>, ...}]->(<ノードY>) で表します。関係を作成する際には必ず向きを指定しないといけません。 ノード・関係のいずれに対しても0個以上の属性を指定することができます。 変数名は後方参照で使わない場合は不要です。

CypherはWebインタフェースや各言語用のライブラリから実行できます。

Cypherによるクエリ

Cypherの利点は、パターンマッチによって柔軟なクエリが発行できることです。

以下は最も簡単なクエリの構文です。

MATCH <変数を含むパターン> RETURN <変数>;

このクエリを実行すると、 MATCH 句で <変数を含むパターン> にマッチする構造を探してオブジェクトを変数に束縛し、 RETURN 句で変数に束縛されたオブジェクトを返します。

以下ではグラフ中のパターンにマッチする構造を 部分グラフ と呼びます。

例えば「ユーザyubessyがブックマークしているエントリの一覧」は以下のクエリで取得できます。

MATCH (:User {name: "yubessy"})-[:BOOKMARK]->(e:Entry) RETURN e;

このクエリを実行すると、「yubessyというnameのユーザがエントリeをブックマークしている」ことを示す部分グラフを探し、見つかったそれぞれの部分グラフに含まれるエントリを変数に束縛し、束縛されたエントリを全て返す、という処理が行われます。

Cypherを使う際には、 () がノード、 ()-[]->() がノード間の関係とだけ覚えておけば、あとは直感的にクエリを書くことができます。 クエリ中には ()-[]-() のように関係の向きを指定しないパターンも使用できます。

はてブグラフの構築

今回はローカルで起動しているNeo4jに、はてなブックマークから取得した以下のようなデータを投入してみました。

  • エントリ: 2015年8月のとある日の「テクノロジー」カテゴリのホットエントリ上位200件
  • ユーザ: 同日時点で上記のエントリを1つ以上公開ブックマークしているユーザ 全4086名
  • ブックマーク: 上記のエントリ・ユーザ間に存在するブックマーク全9301件

エントリのデータはホットエントリRSS、ユーザとブックマークのデータはエントリー情報取得APIを用いて取得しました。 データ取得の際はサービスに負荷をかけないよう、アクセスは直列に行い、10秒以上のインターバルを設定しました。

Neo4j上でのデータ表現は次のようにしました。

  • ユーザ: (:User {name: <ユーザ名>})
  • エントリ: (:Entry {url: <URL>, title: <タイトル>})
  • ブックマーク: (<ユーザ>)-[:BOOKMARK {comment: <コメント>, timestamp: <ブックマークした日時>, tags: <タグ一覧>}]->(<エントリ>)

はてブグラフに様々なクエリを発行してみる

以下では構築したはてブグラフに対し、Cypherを使って様々なクエリを発行してみます。

Neo4jのWebインタフェースは非常に優秀で、実行結果をグラフ図として出力してくれます。クエリと合わせてこのグラフ図も載せています。

あるユーザのブックマーク一覧

先程と同様のクエリですが、ラベルと変数が少し異なっています。

今回のデータベースに存在する関係は BOOKMARK のみであり、関係は必ずユーザからエントリに向けて張られるため、パターン中に関係とその向きが含まれていれば、ラベルは省略できます。

また、実行結果には RETURN 句で指定した変数に束縛されたオブジェクトしか含まれないため、Webインタフェースでグラフ図を描画するには、描画したいオブジェクトを変数に束縛するする必要があります。

MATCH (u {name:"yubessy"})-[b]->(e)
RETURN u, b, e

実行結果は以下のようになります。緑・青それぞれの丸がユーザ・エントリを示すノードです。

f:id:yubessy:20150914135520p:plain

タイトルに"JavaScript"を含むエントリに対する、"JavaScript"というタグの付いたブックマーク一覧

ノードや関係につけた属性値は WHERE 句による絞り込みに利用できます。

Cypherには豊富な種類の演算子が揃っており、正規表現も使えます。 また、属性値にリストを入れることもでき、それに対して IN 演算子を適用することもできます。

MATCH (u)-[b]->(e)
WHERE e.title =~ ".*JavaScript.*" AND "JavaScript" IN b.tags
RETURN u, e, b;

実行結果では、ユーザ名は適当な番号に置き換えています。 図がそれらしくなってきました。

f:id:yubessy:20150914135524p:plain

あるユーザの総ブックマーク数

SQLと同様に COUNT 等の集約関数を実行できます。

MATCH ({name:"yubessy"})-[]->(e) RETURN COUNT(e)

このクエリはノードや関係を返していないのでグラフ図は描画されません。

8

あるユーザがブックマークしているエントリのうち1つ以上をブックマークしているユーザ(name順上位10件)

このクエリは言葉で表現すると少し複雑ですが、パターン記法のおかげで何を求めているかが直感的にわかります。

上位10件としているのはそのままだと非常に多くのユーザが返ってしまうため、 またユーザname順としているのはなるべく異なるエントリがグラフ上に描画されるようにするためで、深い意味はありません。

MATCH (u {name:"yubessy"})-[b1]->(e)<-[b2]-(o)
RETURN u, b1, e, b2, o ORDER BY o.name LIMIT 10

真ん中の「831」となっているのが私(id:yubessy)です。

f:id:yubessy:20150914135530p:plain

あるユーザがブックマークしているエントリのうち7つ以上をブックマークしているユーザ一覧

最後の例は少し複雑です。

今回は新しい構文、 WITH 句を使います。 クエリを句ごとに説明すると、

  1. MATCH (u {name:"yubessy"})-[]->()<-[]-(o)
    • パターン「yubessyがブックマークしているエントリをユーザoがブックマークしている」にマッチする部分グラフを取得
  2. WITH u, o, COUNT(*) as c
    • 得られた部分グラフを (u, o) の組み合わせ毎にグルーピングし、各グループに含まれる部分グラフ数をcとする
  3. WHERE c >= 7
    • 部分グラフ数が7以上のグループのみを選択する
  4. MATCH (u)-[b1]->(e)<-[b2]-(o)
    • u, oに束縛されたオブジェクトの集合に対し、改めてパターン「uがブックマークしているエントリeをoがブックマークしている」にマッチする部分グラフを取得
  5. RETURN u, b1, e, b2, o
    • 部分グラフ中の各変数に束縛されたオブジェクトを返す

という感じでしょうか。厳密にはちょっと説明が怪しいかもしれません。

7という数はグラフ図がいい感じになる値を選んだだけで、深い意味はありません。

MATCH (u {name:"yubessy"})-[]->()<-[]-(o)
WITH u, o, COUNT(*) AS c
WHERE c >= 7
MATCH (u)-[b1]->(e)<-[b2]-(o)
RETURN u, b1, e, b2, o

実行結果中のノードの配置はわかりやすいように編集しました。 左側の緑丸の集合が取得したかったユーザの一覧です。 ブックマークを示す矢印が壮観ですね。

f:id:yubessy:20150914135536p:plain

まとめ

Neo4jにはてなブックマークのデータを入れて簡単なクエリを試してみた、という話でした。

グラフ構造は身の回りの至る所に存在しますが、グラフデータベース自体はあまり普及していないようです。これから使う人が増えて、情報がどんどん出てきたらいいなと思います。

タスク管理をTodoistからWunderlistに乗り換えた

※以下は自分の利用ケースにおける主観的な感想です。 仕様は今後変わる可能性があります。

ちょっと前にタスク管理をApple標準のリマインダーからTodoistに乗り換えた。 最初はTodoistに満足していたが、使っていると時折痒いところに手が届かないことがあった。

そこで今度はWunderlistに乗り換えてみると、感じていた不満がほとんど解消されて幸せになることができた。

Todoistの不満点

有料版限定機能が多い

次の機能はTodoistでは全て有料版でしか使えない。

  • 完了したタスクの閲覧
  • タスクにラベル付与
  • タスクに時刻指定のリマインダーを指定
  • タスクにメモを付与
  • タスクにファイルを添付

Wunderlistではこれらと同様の機能を全て無料で使うことができる。

またTodoistでは、これらの機能がメニューに表示されているのに、使おうとすると「この機能はプレミアム限定です」と言われてフラストレーションが溜まることが多かった。

サブタスク機能が使いづらい

Todoistのサブタスク機能は、タスク間に階層構造を定義するものとなっている。 こうすることでサブタスク毎に期日を設定したりできるが、逆に表示がわかりづらくなってしまうことがある。

例えば次のようなタスク階層の場合、

  • メイン: 報告書提出 (期日: 来週)
    • サブ: 作成 (期日: 今日)
    • サブ: 上司に確認 (期日: 3日後)
    • サブ: 提出 (期日: 来週)

「今日」のビューでは「作成」というタスクが表示されるだけで、この親タスクが何なのかぱっと見ではわからない。

Wunderlistではサブタスク機能は有料だが、無料でもタスクに細かいチェックリストを付与することができる。 チェックリストは親タスクを選択したときだけ見れるようになっており、チェック項目毎に期日を設定したりはできないが、今のところこれで用は足りている。

タスクの分類方法が「プロジェクト」のみ

個人のタスク管理ではタスクを「仕事」「趣味」といった単位に分類したいことがあるが、これを「プロジェクト」と呼ぶのには少し違和感がある。

Wunderlistはタスクをまとめたものは単に「リスト」であり、さらにリストを「フォルダ」に分類することができるので、様々な使い方に対応できる。

Todoistのほうが良かった点

Wunderlistに乗り換えることにしたものの、Todoistのほうが優れていた点もいくつかあった。

ルック&フィールについてはTodoistのシンプルで無機質なもののほうが好みに合っていた(なので当初は両方を比較してTodoistを選んだ)。 また、スマホ版ではスワイプでタスクを完了にできるのも良かった。

その他

今のところ無料版かつ個人利用のみなので、共有などの機能を使ってみればまた評価は変わるかもしれない。

リンク

第1回データサイエンス・カップ 2015 春

機械学習Jリーグの観客動員を予測するコンテストで3位になったので発表会に行ってきた。

datasciencelab.jp

前から機械学習のコンテストには興味があったけどなんとなく敷居が高くて勇気が出なかった。 今回のは学生向けだし手軽にできそうなので、ものは試しと思って参加してみた。

発表会は上位者の発表とか本職の人の講評とかとても参考になった。 1位のid:puyokwにあとでコード見せてもらって、Rも悪くないなと思い直した(自分は懇親会でひたすらPython3推しまくってた)。GBM/xGBM勉強したい。

自分のモデリングの反省としては、生データをもっと綿密に見ていればよかったと思う。 トレーニングデータに無観客試合が混じってたり、今季J1に初昇格したチームがあったことに気づけばもう少し改善できたはず。

許可をもらったのでコードと発表資料は公開しておく。

github.com

数ヶ月後に自分で見なおして「こんときは全然だったな」と思えるようになってたい。

Web系インターンにいくときの準備

はじめに

夏休みにいくつかのWeb系インターンに行ってきた。
会社の規模も内容も期間もいろいろだったけど、どこも楽しかったし、HadoopとかElasticSearchとかのいろんな技術に触らせてもらえて面白かった。
貴重な時間を割いていろいろ教えてくださった社員さんや、交通費や給与を出していただいた会社には本当に感謝するばかりです。

それぞれの内容については、あまりしゃべってはいけないないこともあるので割愛する。
メモとしてインターンに行く前にやっておいて良かったこと、やっておけば良かったことを書いておく。

自分用の設定をまとめておく

特に1週間とか期間の短いインターンで、会社が用意してくれるコンピュータを使って開発する場合、自分の環境をポータブルにしておくとスムーズに開発が進められる。

dotfiles

GitHubかBitbucketにdotfilesレポジトリを作って置いとくと便利。
ついでに setup.sh みたいなのを用意してGitHubからのクローンやシンボリックリンクを自動化しておくとより便利。

  • シェル: .bashrc, .zshrc など
  • エディタ: .vimrc, .emacs など
  • ターミナル仮想化: .screenrc, .tmux.conf など
  • その他: .gitconfig など

その他

OSのキーボードショートカットやトラックパッドの動作がいつもと違うと地味に気になるので、自分の設定をどこかに書き出しておく。
あと日常的に使ってるツールは一覧とインストール手順をまとめておくといい。
brew-caskとかを使うのもアリ。
自分はMacでiTerm2, Alfred, ShiftItとかを常用していたけれど、最初のインターンではdotfilesしか準備してなかったので、この辺もまとめておけばよかったと切実に後悔した。

ちなみにiTerm2は Preferences -> General -> Save Settings to Folder で設定をエクスポートできる。

知っておくべきこと

当然、Webプログラミングに関する次のような最低限の知識・スキルは身につけておくべき。

開発上触れることが多いツールについても知っておいたほうがいい。

  • バージョン管理とチーム開発: Git, GitHub
  • SSH接続: ssh, scpコマンド
  • リモート上で動くエディタ: VimEmacs
  • ターミナル仮想化: screenかtmux
  • パッケージ管理: yum, apt-getなど

使うことになる言語やフレームワークインターン先によって様々なので、それよりMVCフレームワークなどの一般的な概念について勉強しておいた方がいい。
言語やフレームワークが違っても基礎にある概念は似たようなものなので、実際に使える言語はひとつとかでもそれほど問題ない。
むしろせっかくの機会だから新しいことに挑戦するのもいいと思う。

その他

種々の手続にいるもの

当たり前だけど、交通費・宿泊費・給与などを支給して貰えるとこだと銀行口座情報や印鑑が要る。

研究室への周知

大学・大学院で研究室に所属している人は予め不在を伝えておく。

おわりに

Web系のインターンは基本どこいっても何か学べることがあるので、しっかり準備して楽しんできましょう。

Sublime Text 3はいつ出るの?

当方VimEmacsも使えないゆとりSublime Textのヘビーユーザなので3の正式版がいつ出るか出るかと心待ちにしてたんだけどなかなか出ないorz

本家のβも2013年12月のリリースで止まってるしもう気が気じゃない...

それでコミュニティを見てたらこんなスレッドを発見。


4月に僕より少し気の短い人が書いたみたい。

「3まだ出ないの?」

When will sublime 3 be released?
Postby toplinuxsir on Mon Apr 28, 2014 4:36 am

The sublime 3 development status is not updated for long time When sublime 3 will be released?

最初はみんな楽観的で

「出せるようになったら出るよ」

Re: When will sublime 3 be released?
Postby jbrooksuk on Mon Apr 28, 2014 9:10 am

When it's ready.

「休ませてあげようよ!」

Re: When will sublime 3 be released?
Postby jbrooksuk on Mon Apr 28, 2014 1:12 pm

It's not dead.

People deserve and need holidays.

って感じだったんだけど、

TextMateと同じ道をたどるんじゃ・・・」

Re: When will sublime 3 be released?
Postby kpublik on Fri May 02, 2014 7:06 pm

Wow, I'm having TextMate flashbacks. Little or vague info from the dev. Forums posts from > apologists and those in denial about the project's status.

TextMate was a paid product too, yet the developer has been dragging out an official 2.0 release for years. Most people have moved on, and for a while that was to SublimeText. However, competitors are on the horizon, some with more resources and a lot more professionalism than > Sublime's developer.

TextMate missed an opportunity to continue to dominate the text editor market, and now it seems > that SublimeText is making the same mistakes.

I paid for ST 2, but doubt I would "upgrade" to 3.0, when (if?) ever that is released.

「みんながお金払わないから・・・」

Re: When will sublime 3 be released?
Postby macjohnmcc on Sat May 03, 2014 5:38 pm

This is what happens when you have a project where only one person is running everything. Especially if the product is not paying for their living expenses.

I suspect that because Sublime Text will let you use it indefinitely without paying that many people use it without paying. There may be a huge user base but I suspect a large number of them do not pay.

Also figure that Sublime Text works on several platforms that it takes more development and testing efforts so expecting constant updates from the sole developer and tester while desirable isn't likely.

だんだん雲行きが怪しくなってきたぞ・・・

とその時。

「開発版の新いビルド出したよ!」

Re: When will sublime 3 be released?
Postby jbrooksuk on Mon May 05, 2014 9:41 am

I just had a dev build update.

おお!死んでなかった!


というわけで、開発はゆっくり進んでるみたい。よかったよかった。