読者です 読者をやめる 読者になる 読者になる

最寄り駅検索APIをつくってみた話

ライフスタイルメディア事業部のエンジニア、博士ことTei1988です。 過去にSolrを使ってみたり、パトランプを回したりしてました。

6月某日に行われたSpeeeKaigi*1では、「最寄り駅検索API」をつくってみた話を発表しました。

ある地点に対する最寄りの駅をたくさん検索したかったのですが、手頃に叩けるAPIを見つけられませんでした。 見つけられなかったので、とりあえず作ってみました。 自前なので無限に叩けるようになりました。わーい🎉

発表資料は以下になります。

speakerdeck.com

残念ながら、入賞ならず、iPadはもらえませんでしたが、実際に使えそう、という感想をいただけたのが嬉しかったです。 また、今回は、PostgreSQL+PostGISで実装しましたが、SolrやElasticsearchでもやってみたいなぁと思いました。 また、駅と決め打ちせずに地物としてより汎用的にすると、もっと使いやすくなりそうな予感がするので、いずれ挑戦してみたいと思います。

以下でソースを公開しています。

github.com

*1:SpeeeKaigiについては、以下をご参照ください。

technica-blog.jp

会社名寄補助ツールを稼働させた話【社内勉強会レポート#6】

neo4j

こんにちは、海外事業部エンジニア『名寄せのkawakubo』ことid:kawakuboxです。

以前、SpeeeKaigi の発表内容の記事で「会社の名寄せにグラフDB(Neo4j)を使ってみた話」を書きました。

technica-blog.jp

その後、実際に名寄せ補助ツールとして開発し、稼働させるに至ったので、その過程を社内勉強会で発表しました。

今回はそのレポートになります。

トークテーマ

会社名寄せ補助ツールを稼働させた話

キーワード

  • 名寄せ
  • Neo4j

発表資料

質疑応答

似てると判断されるデータのマッピングデータの自動生成などはやっていないのか?

まだ曖昧な検索結果なので、マッピングデータの生成には人の目を介在させたい。

検索にかかる時間は?

総ノード数は 60,000ノード、総リレーション数は 300,000リレーション この状態で100件を上限に検索する処理は、100ms とかそのくらい。

インポートにかかる時間はどのくらい?

インデックス(ノード作成)にかかる時間は、10,000件のマスタ取り込みで 10分程度。 単語間の関連を作成するのにかかる時間は、20,000ワードくらいで4~5時間程度。

20,000 x 20,000 の突き合わせは数日経っても終わらないので、極端に文字数が離れている単語(5文字と10文字みたいな)やつは、レーベンシュタイン距離をとるまでもないので、あらかじめ除外していたりはしている。

単語の重みをつける方法はどうするのか?

日本で言うところの 株式会社 とか 有限会社 みたいな一般ワードのスコアを下げるようにしたり、全ワード中の登場回数が多いもののスコア調整したりするようなオーソドックスなものを考えている。

所感

発表したことで、ワード重み付けについて tf-idf, 単語ベクトル といったアドバイスをもらったので、検索/サジェスト精度を上げるためにどう調理できるかに取り組みたいです。

最近、立て続けに Neo4j について社内発表重ねているので、プロジェクトに導入の検討してみるみたいな話が上がってきたのは喜ばしいことです。

経路問題に置き換えるとスマートに解決できるものはまだまだあると思っているので、いろんなデータモデルを考えてみたいです。

キュレーションサービスにおけるRDBとNoSQLの使い分けを紹介

SpeeeKaigi

こんにちは!リードエンジニアのid:eva-hashimotoです。

先日行われた SpeeeKaigi で「キュレーションメディアにおけるMongoDB事例」を発表しました。

technica-blog.jp

これは、あるキュレーションサービスを2年ほど運用してきた中で、大きなトラブルやアーキテクチャ変更が発生することなく稼働しているので参考として見ていただければと思います。

キュレーション記事のデータ

みなさん1度はキュレーションサービスの記事を見たことがあると思います。しかしデータ構造まで考えて見る人は少ないと思うのでまず説明します。

f:id:eva-hashimoto:20160824163737p:plain

記事のデータとしては大きく二つ分類できます。

  • タイトルやディスクリプションなどの共通データ

  • 記事自体を構成するためのオリジナル文章や引用、画像、動画などの様々なパーツ

このデータをRDBを用いて管理する場合の正規化は雑に考えると二つあるかなと。

パターン1

記事テーブルと各パーツの種類ごとに正規化する

記事テーブル

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

見出しパーツテーブル

記事ID 表示場所ID 見出し
1 1 PV伸ばすための方法
1 4 Analyticsで分析しよう
2 1 なぜRubyなのか?
2 5 エンジニア文化の作り方

画像パーツテーブル

記事ID 表示場所ID 画像タイトル ファイル名
1 3 エンジニア全員 eng.png
3 4 ロゴ logo.png

引用パーツ、youtubeパーツ・・・・and more

パターン2

記事テーブルとパーツを1テーブルで管理

記事テーブル

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

パーツテーブル

記事ID 表示場所ID type text url パーツの種類分・・
1 1 見出し PV伸ばすための方法
1 2 説明文 読むユーザを意識する
1 3 画像 エンジニア全員 eng.png
2 1 見出し なぜRubyなのか?

私の所感ではパターン1を選ぶ方が多いイメージです。

記事を表現するパーツの種類が増えたり変わったりすることで連携するテーブルが多くなるしカラム変更も増えるデメリットがあるがRDBだけならこっちかなと。

パターン2はパーツテーブルという概念がまとめられているが、パーツの種類によって扱うデータが違うため非正規化されておりカラム構成がぐちゃぐちゃになる。

私たちのサービスではパターン2でデータ部分をスキーマレスにする設計にしました。そこでスキーマレス部分のデータを扱うミドルウェアとしてMongoDBを利用しています。

MongoDBを利用したパターン

記事テーブル (RDB)

記事ID タイトル サムネイル ディスクリプション
1 タイトル1 aaa.png エンジニアブログです
2 タイトル2 bbb.png SpeeeはRubyを使ってます
3 タイトル3 ccc.png MongoDB活用について

パーツテーブル (RDB)

記事ID 表示場所ID type obj_id
1 1 見出し obj_001
1 2 画像 obj_002
1 3 twitter obj_003

パーツデータ (MongoDB)

{ Obj_id:”obj_001”, text : ”見出しです” }
{ Obj_id:”obj_002”, title : ”エンジニア”,  url : ”eng.png” }
{ Obj_id:”obj_003”, id : ”@hs”  tweet_id : 1234 }

スキーマレスの利点を生かして各データが持つべきプロパティを適切に表現できます。 こうすることで今までパーツの追加、変更でRDB側のメンテナンスコストは少なく設計とプログラミングで悩むことが少ないです。

デメリットとしてはデータ領域のミドルウェアが増えることによる学習コスト、運用コストが増えることとRDBのリレーショナル性を捨てることになります。この辺はトレードオフなので仕方ないですが十分なメリットだったと感じています。

なぜMongoDBだったのか

当サービスではMongoDBの利用方法として本来はページ単位のキャッシュデータ先として検討していました。

  • 記事のデータ
  • アクセスランキング
  • レコメンド など

それぞれのキャッシュデータ先として利用するだけではなくスキーマレスという性質と先ほど説明した非正規データの格納先に最適ではないか?という発想になった次第です。

キャッシュ先として候補に上がったKVSは幾つかありますが、データの格納、検索性とサーバのクラスタ構成の仕組みと障害時のクライアント動作としてMongoDBが一番理想に近い形だったので選定になりました。

選定内容、検証をくわしく!・・・説明するとこの記事では長くなるため、私に直接聞いてくださいw

エンジニアとしてどんなサービスも手を抜かず適切に技術を選択することでより良いサービス価値を追求していきたいと思います。

ソニックガーデンさんと大LT大会をした

Webマーケティング事業部エンジニアの@hatappiです。

弊社では毎週水曜日にエンジニアMTGを行っており、社内の中で手をあげた人が自身の業務で得た技術などの 知識を発表しています。 お盆明けのエンジニアMTGでは普段からお付き合いのある株式会社ソニックガーデン@mat_akiさんと@mah_labさんをお招きしてLT大会を行いました。

発表スライド

@mat_aki

speakerdeck.com

@kawakubox

speakerdeck.com

@anoChick

speakerdeck.com

@hatappi

speakerdeck.com

所感

今回LT大会にご参加いただいた株式会社ソニックガーデンも含め 弊社では外部のエンジニアの方と一緒に働く機会が増えてきており、様々な刺激をもらっています。 今後もLT大会は開かれると思うので、色んな方が発表するような文化が出来ると良いですね。

↓株式会社ソニックガーデンの松村様のブログ↓

Speee さんのエンジニアミーティングに潜入させていただきました - Small Start

会社の名寄せにグラフDB(Neo4j)を使ってみた話

neo4j SpeeeKaigi

こんにちはっ、海外事業部エンジニアのid:kawakuboxです。

先日行われた SpeeeKaigi で「会社名の名寄せにグラフDBを使ってみた話(wip)」を発表しました。

名寄せという作業は、最終的には人手に頼らざる所が少なからず残ってしまうと思います。

この最後の人の手による作業コストを軽減するために、何かしらの技術的な解決ができないかと思いました。

発表時点では構想段階で簡単な検証にとどまっていましたが、その後実際に補助ツールという位置づけで稼働させるまでいたりました。

このスライドはその発表当時のものになります。

SpeeeKaigi については、以前の記事をごらんください。 technica-blog.jp

トークテーマ

文字列ベースの名寄せ解決へのグラフDBを用いたアプローチ

キーワード

  • 名寄せ
  • Neo4j

発表資料

質疑応答

結果の検証はどうすると良いのでしょう

人手による名寄せ作業の補助ツールという位置づけなので、検索結果に対しての100%の保証はしていないです。 ただ、検索結果のなかから選ばれた名寄せ結果を学習するなどするのも良さそうに思います。

語順は考慮してますか?

単語に分解した時点で語順は無視しています。

ノード増えるとめちゃ計算量増えそうなんですが、クラスタ製品とかあるんでしょうか?

有償ではありますが、クラスタ構成、High Availableな構成などをサポートした Enterprise版 が提供されています。

そもそも会社名マスタって当該国内で管理してないの?

ディレクター側で官民含めて調査してもらったのですが見つかっていないです。

まだ実装できていない、今後精度を上げるアイディアなどあればぜひ。

SpeeeKaigi時点では、スライドに載せたものがすべてアイディアはなかったのですが、今は単語の重要度などを考慮に入れることを考えています。

所感

このスライドを発表してから「名寄せのkawakubo」という二つ名を頂戴しました。

桂さんに面白いテーマだったとコメントもらったりしたので、このテーマで臨んでよかったと思います。

また、実際に稼働させてサービスに貢献しているかどうかが選考において重要視されたので、次回は構想ではなく実績ベースで語り賞品ゲットしたいです。