タグ別アーカイブ: groovy

GrailsからSolrを呼び出すサンプル

| コメントをどうぞ

今年も残すところあと6時間ほどになりました。
今年一年を振り返ると、苦しいこと、辛いこと、、、あれ、目から熱い水がこぼれてくるぞ。
どうもこんにちわ、DiceK Mikamiです。

さて、今年最後のテーマは“Grailsを使って、Apache Solrで検索したデータを取得する”です。
 
 

Apache Solrとは

Apache Solrは、Apache Luceneをコアに持つJavaで書かれたオープンソースの検索エンジンです。国内外の大規模検索サービスで利用実績を持ちます。
国内で言えばAmebaや価格.comなどで使われているそうです。
Solrの特徴として、ファセット検索が挙げられます。
ファセット検索(ファセットナビゲーション、ファセット分析とも)とは、様々なカテゴリー(例えば、分類や期間)を前もって用意しておき、それをユーザーが選択することで検索を行うと言うものです。
また、その検索条件もヒット数などに基づいて提供されるので、“ハズレ”がありません。
「検索したはいいけど1件もヒットしなかった」などということは、このファセット検索においてはありえないのです。
Solrはこのファセット検索のインターフェースを持っています。
 

環境

  • Grails: 2.2.0-RC1
  • Java: 1.7.0_10-ea
  • Apache Solr: 4.0.0
  • solr-solrj: 4.0.0-BETA

 

サンプル

さて、RESTインターフェースを持っているのであれば、AjaxリクエストなりHTTP Clientなりで接続すれば良い訳ですが、それではあまりにも面白くない。
ということで、今回はSolrが持っているJavaクライアントsolrjを利用してみようと思います。
イメージは下図のような感じです。


 

Mavenリポジトリから取得する設定

Grailsには膨大な数のプラグインが存在します。
もちろんその中にもsolrjはあるのですが、なんとも残念なことに古いものしかありません。
ですので、BuildConfig.groovyに少し細工をしましょう。

/grails-app/conf/BuildConfig.groovy

dependencies {
    compile 'org.apache.solr:solr-solrj:4.0.0-BETA'
}

これで起動時にsolrjをMavenリポジトリからダウンロードしてくれます。
(サンプルでは4.0.0-BETAとなっていますが、適宜gradleの記法にあわせて書き換えて下さい)
 

実際に利用する

今回はコントローラーに実際のコードを入れてみます。

class SolrController {
    def index() {
        def url = 'http://localhost:8389/solr/collection1'
            
        // サーバーを作成
        SolrServer server = new HttpSolrServer(url)

        // パラメータを設定
        SolrQuery query = new SolrQuery()
        query.setParam('q','*:*')
        query.setParam('facet','true')
        query.setParam('facet.field','compName_s')
        
        //リクエスト
        QueryResponse resp = server.query(query)

        //レスポンスの処理
        ['queryResults': resp.getResults(), 'facetField': resp.getFacetFields()]
    }
}

たったこれだけでSolrから検索結果を取得できます。
また、このサンプルではHttpリクエストを利用していますが、EmbeddedSolrServerクラス(ローカルにSolrがある場合に高速にアクセスする)やLBHttpSolrServerクラス(ロードバランスを考慮して、呼び出しSolrを選択する)といった複数の呼び出し形態がありますので、Solrがどのような構成で存在するかによって適切なクラスを利用できると言うのも魅力的です。
今回はGrailsでの利用方法をサンプルとして紹介しましたが、ライブラリ自体はJavaですので、Javaアプリケーションにもすぐに取り込めるかと思います。
参考までにGitHubにサンプルコードを公開いたします。
 
 
最後になりましたが、今年一年、私の駄文にお付き合いいただきありがとうございました。
懲りずに来年も書ければいいなぁなどと寒空を眺めております。
ともあれ、皆様よいお年をお迎え下さい!!
 

参考URL

Apache Solr
Maven Repository – solrj
Solrjサンプルコード集
サンプルコード(GitHub)

vert.xでWebSocketする

| コメントをどうぞ

ある昼下がり、私は ラオウ PMからこうお達しを受けたのです。

「お前のような輩は、WebSocketを使った通知サーバーをつくればいい」

このブログは、そんな指令を受けたプログラマー4時間分の記録である。
こんにちわ、DiceK Mikamiです。
 
 

今回の目的

今回は、WebSocketを通知に利用できないかと言うところが出発点になります。
WebSocketと言えばnode.jsですが、今回はそれ以外のやり方を模索したいと思います。
具体的に実現したいことは以下のような図になります。

勘の良い方はお気づきと思いますが、Pusherと同じです。
ただし、Pusherのようなクラウドサービスにも依存したくありませんし、node.jsはまだ利用したくないという命題がありますので、第3の道としてvert.xを利用します。
 

vert.xとは

vert.xとは、「JVM上で動作する次世代の非同期でスケーラブルな並列処理アプリケーションのためのフレームワーク」だそうです。
平たく言うと、「JVM上で動作するnode.js」だと思っていただいて問題ないかと思います。
また、JVM上で動作するとありますが、開発者は複数の言語を利用することができます。
例えば、RubyやPythonなどと言った流行りの言語でも利用できます。
vert.xではSocketJSをサポートしており、これを使うことでWebSocketの利用を実現できます。
 

実装環境

  • vert.x: 1.3.0-final
  • Java: JDK1.7.0
  • Groovy: 2.0.5
  •  

groovy実装を使う

vert.xに含まれているサンプル「 eventbusburidge 」を改良して、実現したいと思います。
groovyで実装した内容は以下のようになります。

import org.vertx.groovy.core.http.RouteMatcher

def server = vertx.createHttpServer()
def route = new RouteMatcher()

route.get('/') { req ->
    req.response.sendFile('notificationserver/index.html')
}

route.get('/vertxbus.js') { req ->
    req.response.sendFile('notificationserver/vertxbus.js')
}

route.post('/deliver') { req ->
    //Postで通知内容が送られてくることを想定
    req.bodyHandler { body ->
        String channel;
        String message;
        def params = body.toString();
        for(param in params.split('&')){
            def keyval = param.split('=');
            switch(keyval[0]) {
                case 'channel':
                    //チャンネルを取得
                    channel = keyval[1] 
                    break
                case 'message':
                    //メッセージを取得
                    message = keyval[1]
                    break
            }
        }

        //受け取ったら指定チャンネルに通知する
        vertx.eventBus.send(channel, ["message": "${message}"]);
    }

    req.response.end();
}

def requestServer = server.requestHandler(route.asClosure())
def sockServer = vertx.createSockJSServer(server)
sockServer.bridge([prefix: '/notif'], [[:]], [[:]])
requestServer.listen(8080)

「 /deliver 」にPOST送信された内容を指定したチャネルに流し込むような形です。
通知を受け取るためには、受け手は前もってそのチャネルをサブスクライブしておく必要があります。
基本的な概念は非常にOpenAjaxHubに似ていると思います。
 
これ以外に通知が届かなかった場合の処理をどうするかや堅牢性を担保するための仕組みなどを組み込む必要がありますが、基本的には目的通りの動きになりました。
 

参考URL

vert.x
SockJS
Pusher
infoScoopガジェットとOpenAjax Hub
 
我がコードに一片の悔いなし!!<もういいよ
注意:この記事の枕部分は脚色されています。

Groovy2 indyのベンチマーク

| コメントをどうぞ

UUURRRRYYYYYYYYYYYY!
 
 
最近Groovyづいているので、グルーヴ感満載ではじめてみようと思い立ったのですが、どうやら大失敗のようですね。
こんにちは。DiceK Mikamiです。

さて、Groovyはバージョン2.0からJava7のinvoke Dynamicに対応するようになりました。
そこでinvoke Dynamicによって最適化されたのだから早くなってるに違いないと思いまして、Groovy2のベンチマークを共有してみたいと思います。
invoke Dynamicがよくわからない方は、参考URLをチェックしてみてください。
 
 

検証環境

OS: CentOS 6.2 (VM)
JDK: OpenJDK 1.7.0_05-icedtea
GDK: Groovy 2.0.2
 
 

検証方法

  1. Groovyのソースリポジトリからソースコードをダウンロード。
  2. ソースコードを解凍し、benchmarkディレクトリ内のコードを実行する。

注:実行に利用するGroovyは、ダウンロードしてきたソースコードをコンパイルしたものです。
 
 

結果

通常版: non-indyと表記
invoke Dynamic対応: indyと表記
Java: Javaと表記
各ラベルの括弧書きは、処理に利用した引数の数です。

文字列表示

アッカーマン関数

配列の足し合わせ

フィボナッチ数列

 
 

考察

自分の目を疑ってしまい5、6回試行してみたのですが、結果はどれも似たり寄ったりでした。
これはテストに重大な問題があったか、そもそもそんなもんなのか判断できませんでした。
ひとまず今回はこの結果を真摯に受け止めてみたいと思います。

Javaは言わずもがなコンパイル言語ゆえに当たり前のように最速です。
ここで気になるのは、indyとnon-indyの差なのですが、ほぼ誤差レベルだということでしょうか。
また、これ以外にもベンチマークはあったのですが、テスト内容によってはnon-indyの方が早かったりしました。
環境としてVMを利用していたということで、動作に不安定さが出たのかもしれませんが、これはほぼ変わらないと考えても構わないような気がします。

今回利用したベンチマークはGroovy2独自の静的コンパイルなどは利用していないものを使いましたので、それらと組み合わせるとまた違った結果になるかもしれません。
また、invoke Dynamicだからこそ速度差がでるといったような処理の場合ならばあるいは差が出てくるかと思います。
と言いましても、今のところ無理してJava7を利用するほどではないかと。
Groovy2のinvoke Dynamic版は正式対応リリースしているわけではありませんので、これからに期待というところかもしれません。
 
 

参考URL

Groovy
JDK 7の新機能:Java仮想マシンにおける動的型付け言語のサポート

Grails + Redis を利用してみる

| コメントをどうぞ

Redisが気になっていたので、RedisをGrailsから扱ってみたいと思います。
今回もまたニッチな内容をお届けしていきます。
 
 

1. 検証環境

  • Grails: 2.1.1
  • Groovy: 2.0.4
  • Java: 1.6.0_35
  • Redis: 2.4.17

 

2. Grailsアプリケーションの設定

コマンドラインからアプリの雛形を作成していきます。
また、利用するプラグインもインストールしておきます。

$ grails create-app GrailsRedisSample
$ grails install-plugin redis-gorm

Redisプラグインというものもありますが、Redis GORMよりもローレベルな階層でRedisを扱う場合にはそちらの方が良いでしょう。
今回は、GORMベースで簡単に扱いたいので、Redis GORMプラグインを利用します。

 

3. Redisとの連携を記述

Redisとの連携を設定ファイルに記述していきます。
今回利用するRedisは、HomeBrewでインストールしたものを利用します。

grails.'redis-gorm'.host="localhost"  //ホスト名
grails.'redis-gorm'.port=6379         //Redosが使用するポート番号
grails.'redis-gorm'.password=""       //デフォルトは空
grails.'redis-gorm'.pooled=true
grails.'redis-gorm'.resources=15
grails.'redis-gorm'.timeout=5000

上記、設定を「 /grails-app/conf/Config.groovy 」に記述しておくとRedisと接続します。

 

4. ドメインクラスの作成

GORMベースで扱うということなので、ドメインクラスを用意します。

$ grails create-domain-class Sample

ドメインの雛形ができたら、以下のようにします。

class Sample {
    static mapWith = "redis"

    String key;
    String value;

    static constraints = {
        key blank:false
        value blank:false
    }

    static mapping = {
        key index:true
    }
}

hibernateと併用するためには、mapWith変数にてredisを指定します。
このドメインはRedis用であることをシステムに伝えるために必要です。
あとは、普通のマッピングクラスのように作成します。
mapping変数にて、指定したものがRedisで捜索するために必要なキー値となります。
実際にRedis内では「 <パッケージ名.ドメイン名>:<キー変数名>:<値> 」という形でキーが登録されます。

 

5. コントローラクラスの作成

表示用のクラスも用意しておきます。

$ grails create-controller Sample

GORMベースに作ると何が便利かと言うと、scaffoldを使えるところです。
簡単に触るだけならばscaffoldで十分です。
作成したコントローラを以下のように変えます。

class SampleController {
    static scaffold = true
}

重要な点は、list()save()なども使えるところです。
また、サービスクラスを用意して、そこでwithTransaction()関数を設定することもできます。

 

補足

私の環境では、上記サンプルでRedisに登録した値はsetとして扱われました。
登録する内容あるいはドメイン設定によってはlistやhashなどで登録できると思います。

 

参考URL

Redis GORM – Reference Documentation
サンプルコード(GitHub)