SpringでNeo4jを利用する際の注意点

spring-bootからNeo4jを利用する場合、spring-data-neo4j(neo4j-ogm)と言ったライブラリでアクセスする事になります。
その際、バグと思われる現象に遭遇しましたので、忘れないように記しておきます。

概要

ValueObjectの配列またはリストをフィールドにもつEntityを作成します。
Neo4jにValueObjectをNodeとして登録させたくない為、フィールドをコンバータで文字列シリアライズしSaveを行いました。
Saveは正常に行われ、Neo4jへのストアされた内容も想定通りのものでしたが、このエンティティをLoadすると、コンバータの処理で型キャストエラーが発生しLoadに失敗します。

詳細

  • LoadできるEntity
    下記のEntityはSave、Loadが行えます

 

  • LoadできないEntity
    下記のEntityはSaveできるが、Load時にエラーが発生する

ValueObjectのListフィールドを追加する。フィールドをコンバーターにより文字列(Json)に変換する

このエンティティをSave後にLoadを実行すると、下記のような例外が発生し失敗します。スタックトレースから、キャストエラーが確認できます。

ここで発生している例外がListからStringへの変換例外だった為、なぜ発生するのか原因がわかりませんでした。Load時に行う処理は文字列(JSON)からValueObjectへの変換のはずです。なぜListを文字列にCastしようとしているのか、、、

原因

スタックトレースを追っていくと、GraphEntityMapperクラスに問題がありそうです。
当該箇所を確認してみます。

配列、Listの場合の分岐があります。どうやら、デシリアライズ先のフィールドがList(配列)の場合のみここで型の変換を行っています。

Neo4jのNodeは、プロパティに数値、文字列、真偽値またはそれらの配列を持つ事ができます。そのため為のロジックだと思いますが、コンバータの有無を確認せずに型変換を行っています。Writerの中でCallされるコンバータは文字列を期待ていますがListが渡される為、文字列にキャストを行おうとし例外となりました。

対応

色々試行錯誤した結果、当該部分を削除する対応を取りました。
テストして見る限り、動作に変わりは無いようなのですが、

まとめ

spring-data-neo4jでList(配列)フィールドにコンバーターを設定する場合は、本現象が発生します。
また、本現象ですが、キャッシュオブジェクトが利用されると再現しませんのでご注意ください。凄くハマりました(–;

「Spring Boot」で「Hello world」

みんな大好きSpringBootを使って「Hello world」。

■1.開発ツールのダウンロード

下記のページからSpring謹製のIDE「Spring Tool Suite」(以下STS)をダウンロードしました。

https://spring.io/tools/sts/all

落としたファイルは、7zipなどのイケている解凍ツールで解凍してください。
パスが深いファイルは、うまく解凍できないツールがあるようなのです。

■2.開発ツールの起動

解凍先の「sts-bundle/sts-x.x.xRELEASE/STS.exe」を実行して、開発ツールを起動します。
sts-dir

こんなツールが起動します。はい、Eclipseです。
sts

■3.「Gradle」プラグインを追加インストール。

みなさん(誰?w)がmavenから移行しているのにならって、私も「Gradle」をインストールしてみました。(Gradle。良い解説書を探してます。)

ゾウさんが好きです。Buildshipを使うことにします。
メニューを以下のように選択してインストールしました。
「Help」->「Eclipse Marketplace」->Findに「Gradle」を入力し検索->「Buildship Integration 1.0」
インストール後、STSを再起動するとプラグインが有効化されます。
sts-marketplace0sts-marketplace1

■4.「SpringBoot」プロジェクト生成ウィザード

STSには超簡単に「SpringBoot」のプロジェクトを作成するツールが用意されています。超便利です。あちょー。

①次のメニューから起動します。

「File」->「New」->「Spring Starter Project」
sts-new-project-0

②STEP1 プロジェクトの基本構成

「Type:」が「maven」になっていたら、「Gradle(Buidship)」に変更してください。他はそのままで大丈夫だと思います。「Next」を押下します。(各項目の意味はいつか探求しますん)
sts-new-project-1

②STEP2 使用するモジュールの選択

ブラウザで「Hello world!」したいので、Web->Vaadinを選択します。

Vaadinは「Java-based Web Framework」(だそう)です。
「javaさえ知っていれば、Html5とかJSを知らなくてもでリッチUIブラウザアプリが作れますよー」という素晴らしいフレームワーク(らしいっす)。Wicketとかと同じ路線ですかね…(いや、むしろWeb版Swing?)
SPA(JS)+REST勢が優位なわが社においてなぜ今・・・。(ФωФ)フフフ・・・。
sts-new-project-2

③STEP3 完了

最後のステップは、何もせずそのまま「Finish」を押下します。
sts-new-project-3

■5.「Hello world!」コードを記述

生成されたプロジェクトを開き、「src/main/java」の「com.example」パッケージに下記のクラスを追加しました。むぅ。Javaですねー。

■6.実行

上記のクラスができたら、実行してみます。
「com.example.DemoApplication.java」を選択し、
コンテキストメニュー(右クリックメニュー)の「Run As」->「Spring Boot App」を選択すると実行できました。(埋め込みTomcatが起動します)
sts-hello-run

■7.ブラウザでアクセス

ブラウザで次のURLにアクセスしてください。
「http://localhost:8080/index.html」
ボタンを押下すると「Hello Workd!」と表示されれば成功です。
sts-run-b

■8.まとめ

「STS+SpringBoot」を使ってコードをほとんど書かず「Hello world!」できましたー。

Solr Cloudを動かしてみる

シーマークの山本です。

Apache Solr は全文検索エンジンとして様々なところで使われており、もはや特殊なプロダクトでは無く、検索機能を実現するならSolrというほどコモディティーとしての広がりを見せています。Solrバージョン5からはSolr Cloud機能が実装され、検索「エンジン」から検索「システム」へと変貌を遂げてきています。

そこで、Solr Cloudを使って検索システムを構築する方法についてまとめていきたいと思います。ただ、Solr Cloudのチュートリアルにある付属のサンプルを動かす方法ではなく、実際の商用プロジェクトで必要になりそうな「こんな時どうする」的なTipsを中心にまとめていきます。

構築する検索サービスの想定(=要件)

商用で提供する検索サービスであれば最低限気にすることではありますが、今回説明していくためのサービス想定、言い換えれば要件を列挙しました。

  1. AmazonのAWSや、Microsoft Azureなどのクラウド環境で複数台のサーバインスタンスを使ってSolr Cloudを構築する
  2. 検索サービスが止まらないよう高い可用性を実現する
  3. 検索サービスで提供する機能が増え、Solrの設定を変更する場合でも簡単に行える
  4. 利用者が増えても検索速度が落ちないよう簡単に負荷分散できる
  5. 検索対象データが増えても検索速度が落ちないよう簡単に拡張できる

こう書いてみると、なかなか大変そうな要件ではありますが、Solr Cloudを使えば、案外簡単にできちゃったりする(かも)のでご安心を。

 

1. 開発環境の構築

まず、「要件1 複数サーバを使って構築すること」をいきなり実現しようとすると、AWSのアカウントだったり費用がかかったりするので、まずは自分のPC上で開発環境をつくるところから始めましょう。

開発環境ですが、私がMac派なので、Macを前提に書いていきます。ただ、Windowsとまるっきり違うかどうかと言えば、あまり差異はないはずです。明らかに違うところは補足を入れます。

1.1 Solrのダウンロード

まずは、Solrのダウンロードです。執筆時点では 6.2.1 が最新でした。

https://lucene.apache.org/solr/mirrors-solr-latest-redir.html

ダウンロードしたSolrをお好きなところに展開します。

 

1.2 検索サービス用のSolr configセット

検索サービスとしてどのようなデータをインデックスし、どのように検索させるかを定義するため、Solrではいくつかの設定ファイルを用意する必要があります。通常のSolrとは異なり、Solr Cloudで利用するSolr設定ファイルセットは、zookeeperという別のミドルウェアに登録し管理することになります。

Solr設定ファイルの内容については、本題からはずれることもあり、Solrダウンロードパッケージに含まれるサンプルである「techproducts」用の設定ファイルをそのまま利用します。既にあるので、それを適当なところへコピーします。

 

次は、Solrの設定から一旦はなれ、Solr Cloudを構成する名脇役 zookeeperの設定についてです。

 

1.3 zookeeperを設定する

zookeeperって初めて聞いたって人もいるかと思いますので、軽く紹介を。

https://zookeeper.apache.org/

Apache zookeeperは、複数のサーバインスタンスで構成される分散システムにおいて、設定情報の同期、グルーピングや名前付けの管理を提供するミドルウェアです。

Solr Cloudでは、Solr設定ファイルの集中管理と配布、Solrサーバの管理(shards / Replica、solr nodeの生死等)をzookeeperが提供しています。

zookeeperのインストールは、上記のzookeeperのサイトからダウンロードして、Solrと同じく好きなところに展開します。(もし、Mac環境でbrewをお使いであれば、brew install zookeeperでインストールも可能です)

執筆時点での stableなバージョンは 3.4.9 でした。

http://ftp.jaist.ac.jp/pub/apache/zookeeper/stable/zookeeper-3.4.9.tar.gz

zookeeperは、検索システムの設定情報や構成情報を集中的に管理しています。zookeeperが止まれば、Solr Cloudも停止します。そこで、zookeeperの可用性を高めるため、zookeeperを複数台のサーバーで稼働させます。できれば、Solr Cloudとは異なる専用サーバを用意することが望ましいです。また複数台と言ってもzookeeperの特性上、奇数台で運用をすることが要件となっています。つまり、3台、5台構成をとることが必要です。開発環境では1台の中で3プロセスを起動するようにしましょう。

まず、3プロセス用のzookeeper設定ファイルを用意します。

そして、格納されるデータディレクトリ(dataDirで指定されているディレクトリ)を作成し、そこに設定ファイルを追加します。

これで、zookeeperを起動する準備が整いました。さて起動させましょう。

一応止めるコマンドも。

これで、zookeeperの準備は整いました。

 

1.4 Solr configファイルセットのzookeeperへの登録

1.2 で用意したSolr設定ファイルセットをzookeeperに登録しましょう。登録する際、zookeeper上で管理するための名前を付ける必要があります。ここでは「techp」としました。

これで、Solr Cloudで利用される設定ファイルセットがzookeeperで「techp」という名前で管理されました。

 

1.5 Solr cloudの立ち上げ

本体であるSolr Cloudを立ち上げましょう。複数台で構成するのでしたよね。開発環境なので、1台で複数インスタンスを立ち上げましょう。今回は4台構成とします。

まず、そのための準備です。

では、立ち上げます。Solrの待受ポートは通常は8983なんですが、4つのインスタンスを立ち上げるため、8983, 8984, 8985, 8986として起動します。

これで、4インスタンスがSolr Cloudとして立ち上がっています。

念のため、停止させるコマンドも。

 

1.6 collectionの作成

Solr Cloudでは、検索データをとりまとめる単位をCollectionと呼んでいます(通常起動のSolrでcoreと呼ばれていたものと同じ概念です)。Collectionを作成しましょう。Solr Cloudでは、複数台のサーバにうちどれか1台に対して操作するだけで、Solr Cloud全体に反映されます。

パラメータの説明です

パラメータ設定内容
-ctechproductsCollection名
-ntechpzookeeperで登録されている設定ファイルセット名
-shards2シャード数。1つのインデックスを複数に分割する場合。通常SolrでいうShardsと同じ意味。
-replicationFactor2レプリカ数。レプリケーションとしていくつコピーを作成しておくかの指定。通常Solrではreplication用Solrの数と同じ意味。
-p8984操作対象とするSolrインスタンス。今回であれば、8983, 8984, 8985, 8986のどれか

 

作成されたことを、Solr管理画面で確認してみましょう。

localhost8983

 

1.6 データの投入

Solr Cloudへのデータ投入は様々な方法があります。これについては本題からはずれるため、サンプルで用意されているデータファイルをコマンドを使って投入してみましょう。ここでも、複数台のうちどれかにデータを投げれば、Solr Cloud全台に反映されます。8984, 8986 に投げてみる例です。

検索できるかどうか、Solr管理画面で確認してみましょう。

solrsearch

できましたね。

今回は、ここまでといたします。残りの部分は、後日アップいたします。

 

antd-initでReact,Reduxのboilerplate作成

ここ数年、Single Page ApplicationはSencha ExtJS、Sencha Architect を使用して構築していました。
ですが、ライセンス費用をかけずにオープンソースで構築できるようにしたいね、ということで、現在、React、Reduxに取り組み中です。
React、Reduxを始めるにあたり、簡単にboilerplateを作成してくれるantd-initが便利だったので、ここでご紹介したいと思います。
このboilerplateは、react, redux, redux-saga, react-router, webpack, babel, css-modules、LiveReload等、React、Reduxの開発に必要なライブラリがひと通り揃っています。
また、UIフレームワークはAnt Designを使用しています。

今回は、Ubuntu14.04に、antd-initのインストールと、boilerplateの作成を行ってみます。
node6系を使用できる環境であれば、antd-initのインストールから開始できます。
エディタはAtomを使用します。

Atomインストール

PPA経由でインストールします。

Ubuntuのアプリケーションから「Atom」を起動します。
初回の起動は少し時間がかかります。起動すればOKです。一旦閉じます。

nvmインストール 

nodeはバージョンによってアプリが動作しない場合もあるため、複数のバージョンを切り替えて使用したくなります。
そこで、複数のバージョンのnodeを切り替え可能な「nvm」を使用すると便利です。
nvmで、nodeのインストール、指定バージョンへのnodeの切り替えが可能となります。
以下でnvmをインストールします。

起動時に読込むよう、~/.bashrc 等に以下を追記します。


コマンドプロンプトを再起動し、バージョンを確認します。


■ nodeインストール
nvmをインストールしたら、nodeをインストールします。
以下でnodeのバージョンを確認し、どのバージョンをインストールするかを決定します。


ここでは、node6.2.2をインストールします。
インストールしたら、バージョンを確認します。


nvmインストールは、以下のページを参考にさせていただきました。
他のnodeバージョンへの切り替え方法等も記載されています。

「nvm で作る Node.js の環境構築(+ Hello world)」<http://arfyasu.hatenablog.com/entry/2016/01/26/212543>

■ antd-initインストール

現在は2系ですが、1系を使用したいため、バージョンを指定してantd-initをインストールします。

次に、boilerplateを作成します。


nodeモジュールがインストールされるため、少し時間がかかります。
作成されたら、boilerplateアプリを起動します。


webpack: bundle build is now finished.が表示されたら、http://localhost:8989/ にアクセスします。
以下の画面が表示されればOKです。

screenshot-from-2016-10-27-160710


■ boilerplateを編集

Todo App を編集してみます。
AtomでantdinitSampleディレクトリを開きます。

▼ タイトルを変更

src/layouts/MainLayout/MainLayout.jsx 9行目
「Todo App」 を「タスク管理」に変更し、ファイルを保存します。
webpackのビルドが実行され、livereloadがファイルの変更を検知し、ブラウザをリロードします。

そのため、ファイルを変更するだけで、ブラウザの表示が更新されます。

 リストのタイトルを追加

src/components/Todos/Todos.jsx 23行目に以下を追加します。

▼ タスクを追加

タスクは、ajaxで取得しています。boilerplateではMockで動作しています。
proxy.config.js 23行目に以下を追加します。

このファイルは変更検知対象外であるため、ブラウザをリロードして確認します。

▼ cssを追加

先程追加したリストタイトルに下線を引いてみます。
src/components/Todos/Todos.less 4行目に以下を追加します。

こちらもブラウザをリロードします。
(再ビルドは実行されますが、リロードされないため)

以下の画面に変更されました。
screenshot-from-2016-10-27-173327

このboilerplateを作成すれば、React、Reduxの開発環境を簡単に整えることができます。
redux-sagaやfetch、reducerもすぐに使用できるようになっているため、Todo Appを参考に、React,Reduxアプリを作成しやすくなります。

Neo4j(グラフDB)

Neo4jに触る機会があったのでちょっと調べた事を書いておきます。

Neo4jとは
・Javaで記述されている
・スキーマレスでデータを登録できる
・データ間の関連を定義、登録できる
・データをCypherと呼ばれるSQLライクな言語で操作できます
・グラフ理論に基づいたデータベース
・関連定義、検索するのが得意

グラフてなんだ?
ノード(Vertices,節点,頂点)の集合とエッジ(edges,枝,辺)で構成され、関連をノードとエッジにより表現したものをグラフと言う,,,らしいです
エッジが向きを持たない場合は無向グラフ
エッジが向きを持つ場合は有効グラフと言われます

無向グラフ:Facebookのフレンド
有向グラフ:Twitterのフォロー
有向-無向グラフ

グラフDBてなんだ?
・グラフ構造を持ったDBはグラフDBと言えるのか
→そういう事では無いらしい
・なので、RDBでグラフ構造を定義してみる
rdb%e3%81%a7%e3%81%ae%e3%82%b0%e3%83%a9%e3%83%95
と、こんな感じになります(ちなみに、DocumentDBでも定義できます)
この場合、Aに隣接する要素(BまたはC)を取得する場合はインデックスツリーを参照しBを特定します
例の場合は単純なので想像しにくいのですが、Facebookの多くのユーザが存在するサービスで、友達の友達に特定の属性を持った人は何人いるか?などを調べる場合、かなりの時間が必要となるでしょう
・では、グラフDBだと
グラフDBでは要素(ノード、エッジ)が隣接する要素のポインタを直接持っています
なので、全体のデータ量が増えたとしても一定のコストで隣接要素を取得することができます
特定のルートノードを起点に関連をたどる事が効率的に行えるといえます

・グラフDBの苦手な事
要素全体に対する処理は苦手です

  • ノードの関連が10以上のノードを取得したい
  • データ全体の平均値を取得したい

まとめ
Neo4jじゃ無くてグラフDBについての記事だよね
関連を中心にデータを操作したいときには有効だよ
データ全体に対する操作は苦手だよ
あまりまとまりの無い文章だったね、、、