冥冥乃志

ソフトウェア開発会社でチームマネージャをしているエンジニアの雑記。アウトプットは少なめです。

follow us in feedly

Embulkで検証中に引っかかったことメモ

前回、こんな感じでRe:dashよりも先にやることがあるだろう、と気づいたわけです。

mao-instantlife.hatenablog.com

というわけでEmbulkで各種データソースの読み込みから始めています。

Embulkとは?

バルクデータローダーです。inputとoutputの形式が各種プラグインで提供されていて *1 、対応可能なストレージの種類が多いのが特長です。

他にも公式サイトのアピールとしては、

などありますが、後者二つはまだ試していません。

いつものごとく、公式ドキュメント見れば事足りるインストールやセットアップは割愛。最近はこの辺で試行錯誤して環境による注意事項書かなきゃいけないようなツールが減ってきましたね、いいことです。

覚えておきたいサブコマンド

  • example
  • guess
  • preview
  • run
  • gem
  • mkbundle

プラグインはグローバルなインストールだけではなくて、プロジェクトごとにGemfileつくってバンドルすることもできるようですね。実行環境をテキストで管理できるのは、作る上では嬉しいことです。

exampleはその名の通り、とりあえずローカル実行可能なデモ用の設定ファイルをつくってくれます。試すのにもデータソース作らないといけないの面倒臭いとかそういうニーズがあるんでしょうね、きっと。

guessが入力ファイルフォーマットの自動で、推測した結果を完全な設定ファイルにして出力してくれます(基本は標準出力?)。が、Elasticsearch用のものなどプラグインによっては未対応のものもあるので、全面的に頼れるわけではないようです。

見つけたプラグイン

MySQLのGEOMETRYタイプ問題

Unsupportedですよ、と。

それはそれでいいんですが、エラーメッセージに column_optionstype: string を追加しろと言ってる割には追加してもエラーで変わらず。エラーメッセージの間違いだったようです。

github.com

で、対応するにはクエリでキャストするなりの工夫が必要です。

gist.github.com

まあ、今回は無理してGEOMETRYタイプを使わなくてもいい案件だったので素直に検索対象から外すことにしました。

Google Analytics APIが有効にならない問題

以下の流れで追加したユーザの認証キーを突っ込んで実行してみたんですがね。。。

  • API Managerでサービスアカウント追加
  • API ManagerでAPIの利用を追加
  • Analyticsにユーザ追加して権限を「編集」に設定
Error: forbidden: Google Analytics Reporting API has not been used in project mallnavi-1352 before or it is disabled.

はあ、そうですか。。。APIのリクエストにはカウントされてるし、ちょっとよく分からない。

迂回路は幾つかありそうですし、となると優先順位は全体像を作ることなので、とりあえず放っておくことにして、digdagとEmbulkを組み合わせてみようかと思います。

*1:中はJRubyで動いているらしくgemでインストールします

データ分析環境を作りかけのメモ

一度リリースしたサービスを成長させるんだったら実際の各種データを元に仮説を立てて検証したいところ。アクセスログやアプリケーションデータやGoogle Analyticsの分析データなど、運用時に種々のデータが蓄積されていきます。それぞれでも有用なデータなわけですが、バラバラなままでは活用が難しいこともあります。データは繋いで使ってこそ、意味がある。

というわけで、データ分析環境をどうやって作るか考えて、ここ数週間、要件を書く合間を縫って検証してきた内容と気づきをまとめます。

想定されるデータソース

現状、扱っているデータソース(Analyticsをデータソースと言っちゃうのはあれですが)は以下三つ。

そして、導入を検討しているものとして

  • Neo4j

があります *1

Re:dash

とにかく異なるデータソースをつなぐ環境が欲しい、というわけでRe:dashの導入を検討しました。

redash.io

Re:dashは様々なデータソースをまとめてSQLでクエリを書いてビジュアライズできるソフトウェアです *2

どうも、クエリの結果はRe:dash側にスナップショットをとってる感じがするので、ビューをつくってグラフやなんかでデータを表示させるためのフロントエンドという操作感。Elasticsearchにおけるkibanaのような位置付けで、もっと多くのデータソースに対応できる、というイメージでいいかと思います。

インストールやセットアップなどは公式ドキュメント通りにできたので割愛します。Docker上に環境作れるのはいいですね。

対応していないデータソースへの対応

結構な数のデータソースに対応しているんですが、それでもまだ対応していないものがあります。今回の検証に関わるところだと、

の二つ。

このような場合に検討するのは、

  • 無理くりロードするクエリランナを書く
  • 対応しているデータソースにインポートしてから読み込む

のどちらか、ですね。まず最初は前者を検討してみることにしました。

Pythonクエリランナ

このような未対応データソースへの対応なのかどうかわかりませんが、Pythonクエリランなというのがあります。

Supported Data Sources — Re:dash documentation

なんか、100%セキュアな状態で使ってね、とか怖いこと書いてますが、ローカルでDockerイメージ立ち上げて検証する分には問題ないでしょう。

実際のPythonでのクエリのイメージはここを読んでみてください。

gist.github.com

他のクエリ結果の取得ができるようですね。 ドキュメントに記載がなかったのでソース見てみましたが、提供されているAPIはこの辺っぽいです。

github.com

get_query_resultの引数がidだけなので、パラメータありのクエリは無理?

Neo4jのクエリを書いてみる

注意:結局できなかったのと、やりながら重要なことに気づいてしまったので中途半端に終わります

neo4j.com

Neo4jはPythonのライブラリがあります。というわけで、クエリを書いてみようと思いました。やってみたことは以下。

  • Neo4jのPythonライブラリをインストールしたRe:dashイメージを作る(イメージのビルドとrunは成功)
  • クエリを書いて実行

クエリはこんな感じです。

from neo4j.v1 import GraphDatabase, basic_auth


  driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "neo4j"))
  session = driver.session()


  session.run("CREATE (a:Person {name:'Arthur', title:'King'})")


  result = session.run("MATCH (n:Person) WHERE n.born >= 1970 RETURN n.name AS name, n.born AS born")
  for record in result:
      print("%s %s" % (record["title"], record["name"]))


  session.close()

これが、どうもライブラリを参照できてないわけです。そもそもPythonクエリランナがどういう参照の仕方をしているかよくわかってないので、pipでインストールするだけでOKなの?とか諸々調査が必要しなきゃいかんかな、と思い始めていたわけですが。。。

ここでふと気づく

で、ここで気づいてしまったわけです。ここまで考えてたことって、本番系を直接データソースとして取り込むやり方の検証なんですよね。何かの拍子にスロークエリ投げてしまったら本番系に影響出してしまう可能性もあるわけです。今更ながらこれはだめじゃん、と。

というわけで、基本的なデータのみ定期的にEmbulkでRedshift突っ込んで読めればいいのでは、ということで今はEmbulkとdigdagの検証に入ってます。この辺が検証終わったらまたRe:dashの検証を再開する予定です。もっと早く気付こう。。。

Embulk — Embulk 0.8 documentation

What’s Digdag? — Digdag 0.8 documentation

*1:導入が決定したわけではないです

*2:一部SQL未対応のデータソースあり。Elasticsearchとか

2016年8月の読書メモ

MPの制約が緩くなったので、何がしたいのかってくらい読んでしまいました。Kindle Unlimitedと図書館が悪い。

今月の読書量

22冊、だと。。。

野田と申します 1巻

スター・レッド

スター・レッド (小学館文庫)

スター・レッド (小学館文庫)

私の恋人

私の恋人

私の恋人

春の呪い

春の呪い: 1 (ZERO-SUMコミックス)

春の呪い: 1 (ZERO-SUMコミックス)

銀河鉄道の夜

ペンギン・ハイウェイ

ペンギン・ハイウェイ (角川文庫)

ペンギン・ハイウェイ (角川文庫)

世界から猫が消えたなら

世界から猫が消えたなら

世界から猫が消えたなら

図解ピケティ入門

世界で戦うプロダクトマネジャーになるための本

ゆらぎの森のシエラ

コンピューターは、むずかしすぎて使えない

コンピュータは、むずかしすぎて使えない!

コンピュータは、むずかしすぎて使えない!

パタリロ 1~2巻

パタリロ!―選集 (1) (白泉社文庫)

パタリロ!―選集 (1) (白泉社文庫)

ダンジョン飯 三巻

ランド 三巻

ランド(3) (モーニング KC)

ランド(3) (モーニング KC)

建築家が見たマンガの世界

トーマの心臓

トーマの心臓1 萩尾望都Perfect Selection 1 (フラワーコミックススペシャル)

トーマの心臓1 萩尾望都Perfect Selection 1 (フラワーコミックススペシャル)

BONES

BONES ― 動物の骨格と機能美

BONES ― 動物の骨格と機能美

屍者の帝国

沈黙

沈黙 (新潮文庫)

沈黙 (新潮文庫)

やつがしら

やつがしら

やつがしら

旅したら豆腐メンタルなおるかな?

モザイクラセン

今月のベスト本

ペンギン・ハイウェイ」一択です。読後も爽やかだし、成長に伴う痛みもよく描かれているし、何より周りの大人がかっこいい。森見登美彦は今まで読んでなかったけど、これから読んでいこうと思いました。

第2回 【岡山】 Atlassian ユーザーグループ 中国地方で発表してきました

augca.connpass.com

まとめはこちら。

togetter.com

スライドは一部出していいのかダメなのかわからないところがあるので、現時点での公開は差し控えたく候。

セッションについて

「Atlassianという言葉が入ってれば、何をやっても良い(誤読」とのことだったので、年末の内容をブラッシュアップしてセッションしました。まあ、スライドの使い回し部分はほぼ前説に相当する部分のみですが。一番言いたかったことは、

ツールは選択に過ぎないから、自分たちでちゃんと選べるチームになろう

ということに尽きると思います。

勉強会について

他のセッションはデモを盛り込んでいたので、Atlassianツール同士の連携の良さを見ることができました。目がGithubredmineに慣れているので、少しデモが早かったですが。JIRAを軸に開発だけではなくて、ビジネスのライフサイクルを回すツールの展開をされているんだな、と感じました。

Portfolio欲しい

デモでは触れられなかったんですが、セッションを聴きながら公式サイトを見てたらPortfolio for JIRAというのを見つけて、俄然欲しくなりました。

ja.atlassian.com

長沢さんもブログで紹介されていますね。

www.evangelism.jp

完全に私が下記エントリでやろうとしてたフローと情報をカバーしてます。

mao-instantlife.hatenablog.com

今までの転記やキャッチアップの人的コストはなんだったんだという。。。いや、もう、買い切りライセンスあるし、チームの人数少ないし、これができるんだったら個人の財布からでも良いよ(デブサミ関西終わってから。

Neo4Jの検証メモ

SpringBoot 1.4が対応したみたいなので、これから先に予定している機能のこともあり、用途の検討も含めて少し使ってみました。なお、SpringBootからの利用ではなく、Neo4Jそのものの検証です。

そもそもNeo4Jとは?

大体以下から大まかに抜粋。

neo4j.com

Neo4j - Wikipedia

レコード(Neo4J的にはNode)と関連のグラフ構造でデータを表現するグラフデータベースです。データ構造がリレーションモデルではないので、当然系譜的にはNoSQLなわけですが、他のNoSQLとは違ってKeyValue形式ではないのが特長です。

で、他のグラフデータベース(ぶっちゃけ他に何があるか知りませんが)と違うのは、

といったあたりで、Enterprise Editionの可用性とともに、この辺結構プッシュしてた感じです。

ライセンス的にはCommunity EditionとEnterprise Editionがあります。クエリエンジンや基本的なデータベースとしての機能において両者の違いはなく、クラスタリングやキャッシュなどの運用面において違いがあるようです。なお、Community Editionは無料。

使ってみての諸々

インストールはダウンロードして展開してアプリたちあげるだけなので割愛。特に困ったことはありませんでした。

基本

先ほども少し触れましたが、データモデルは「ノード(Node)」「コネクション(Connection)」で表されます。ノードとコネクションのデータ構造管理とクエリ発行がグラフデータベースシステムの役割です。

ノード

今までのRDBMSで言えばレコードに相当します。考え方としてタイプよりもインスタンスを元に作成されるので、レコードほどスキーマ基準の考え方をしなくてもいいようです。

ノードは属性とラベル(グルーピングのために使ったり、スキーマっぽく処理したり)を付与することができます。ノードの属性に指定可能なタイプは以下の通りです。

  • boolean
  • byte
  • short
  • int
  • long
  • float
  • double
  • char
  • string

Javaで作られているので、この辺は基本的にJavaと一致すると思えば良いかと。

コネクション

ノードとノードを結ぶ関係のことで、RDBMSなら外部キーやら制約やらに相当するかと思いますが、Neo4Jではコネクションそのものに値が持てます。コネクションもインスタンスベースとなるので、ラベルなどによるグルーピングはできますが、厳密なスキーマ運用はシステム上ではしていないです。

インデックス、トランザクション

構文やプロシジャのサンプルにもありましたが、今回は使っていません。全文検索インデックスもある模様。

Neo4J用クエリ Cypher

御本尊はここ。

neo4j.com

細かいシンタックスに触れると単に公式ドキュメントの引き写しになるので、使ってみたときのハマりどころとか気づきを主に。

ノードとコネクションのCRAETE

例えば、知り合い同士の関連を表す場合(公式のサンプルから引っこ抜いてきました)。

CREATE (js:Person { name: "Johan", from: "Sweden", learn: "surfing" }),
(ir:Person { name: "Ian", from: "England", title: "author" }),
(rvb:Person { name: "Rik", from: "Belgium", pet: "Orval" }),
(ally:Person { name: "Allison", from: "California", hobby: "surfing" }),
(ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir),
(js)-[:KNOWS]->(ir),(js)-[:KNOWS]->(rvb),
(ir)-[:KNOWS]->(js),(ir)-[:KNOWS]->(ally),
(rvb)-[:KNOWS]->(ally)

(js:Person { name: "Johan", from: "Sweden", learn: "surfing" }) がノード、 (ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir) がコネクションの定義です。

  • ノードのシンタックス(value:Label {属性1:値,属性2:値})
  • コネクションのシンタックス(ノード条件)-[value:TYPE {属性:値} ]->(ノード条件)

コネクションのノード条件については省略可能で、シンタックスはノードと同じ、条件の value 以外は省略可能です。

ノードもコネクションもクエリ投げる時の注意点は value で、同一ステートメントの中でしか有効じゃありません。というか、ノードに value で名称がつくわけではないようです。これに気づかずにつまんないハマり方をしまして、一度CREATEでノード作った後に別のステートメントでコネクション作ろうとして同じ value 指定してCREATE投げたら、当然別ステートメントだから参照されず、目的のノード間に対するコネクションが作られず、宙ぶらりんな謎ノードがこれでもかと作られました。

というわけで、一度作ったノードに新しくコネクションを貼るときには、MATCH とCREATE を組み合わせて使いましょう。

すでにノードが存在する可能性があるときはMERGEを使います。検索してみて、見つからなければCREATEしてくれます。

スキーマレスなので、属性のあるなしでエラーは多分出ないです。ぶれても大丈夫。

検索の基本、MATCH

ノードとコネクションの関係を表すパターンで検索をします。

ノードの条件検索

ノードに設定された名称を条件に検索します。

MATCH (ee:Person) WHERE ee.name = "Emil" RETURN ee;

コネクションのパターンから検索

ある条件のノードと KNOWS という関係を持つノードを検索します。ルートになるノードに検索条件をつけます。

MATCH (ee:Person)-[:KNOWS]-(friends)
WHERE ee.name = "Emil" RETURN ee, friends

RETURN は複数の項目セットを返すことができます。

コネクションのパターンは一つで終わらせる必要はありません。友達の友達から趣味が合いそうな人をお勧めするみたいなクエリも書けます。

MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)
WHERE js.name = "Johan" AND surfer.hobby = "surfing"
RETURN DISTINCT surfer

関連の長さを指定するパターン

関係の本数が3以上で5を最大とする関連、みたいな長さを基準にしたパターンも可能。

(a)-[*3..5]->(b)

実行計画(PROFILE or EXPLAIN)

クエリに PROFILEEXPLAIN をつけると実行計画を出してくれるようです。

ユーザ定義プロシジャ

Neo4Jではユーザ定義プロシジャーを作って CALL で呼ぶこともできます。必要なAPImavenリポジトリで公開されていて、Javaのクラスで作ります。

neo4j.com

関数の読み込みも、プロシジャーを作ってjarに固めてpluginディレクトリに入れておけばOKです。

とりあえずサンプル写経して、自分でプロシジャを作ってみたリポジトリがこちら。

github.com

普通に gradle build してできたjarをpluginに入れてNeo4Jを起動すれば関数が使えました。

テストをサポートするライブラリなんかも用意されています。サンプル通りにテストコード書いて実行すると若干起動が遅い上に以下のような出力が出るので、jerseyでNeo4Jを起動しているのかもしれません。

8 08, 2016 1:11:41 午後 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
情報: Initiating Jersey application, version 'Jersey: 1.19 02/11/2015 03:25 AM'
8 08, 2016 1:11:41 午後 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
情報: Initiating Jersey application, version 'Jersey: 1.19 02/11/2015 03:25 AM'
8 08, 2016 1:11:42 午後 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
情報: Initiating Jersey application, version 'Jersey: 1.19 02/11/2015 03:25 AM'


Process finished with exit code 0

とりあえず単体で呼ぶことはできたんですが、例えばこれをMATCHの結果から計算してそのままセットする、みたいなことは、まだCypherシンタックスがよくわかってないのでできませなんだ。。。

まあ、そもそもですね、こんな関数的なプロシジャ作るべきではなくて、もっとバッチっぽい用途でビジネスロジックをデータベースエンジン側に寄せるようなやり方に使うべきで、プロシジャの中でクエリ投げろ、ということですね、きっと。

まとめ

まあ、SpringBootのサポート状況はさておき、グラフデータベース自体は結構使えるんじゃないかという感触です。可用性については、公式サイトの導入事例が結構でかいところなので、現段階ではあまり気にしてないというか。