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

PGは電子羊の夢を見るのか?

データとパターンのあいだ

Elasticsearchを準備してKibanaでグラフを表示するまで

プログラミング

1. Elasticsearchをインストールする

$ brew install elasticsearch

※ 2015/10/30現在、brewでインストールされるelasticsearchは1.7.3。

2. Elasticsearchにプラグインをインストールする

今回インストールしたのは、起動用のスクリプト形態素解析エンジンのkuromoji。

$ /usr/local/bin/plugin -install elasticsearch/marvel/latest
$ /usr/local/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/2.7.0

3. Elasticsearchを起動する

$ elasticsearch

4. AnalyzerとMappingの設定

今回は以下のように設定。

{
  "settings": {
    "analysis": {
      "filter": {
        "pos_filter": {
          "type": "kuromoji_part_of_speech",
          "stoptags": [
            "助詞-格助詞-一般",
            "助詞-終助詞"
          ]
        },
        "greek_lowercase_filter": {
          "type": "lowercase",
          "language": "greek"
        }
      },
      "tokenizer": {
        "kuromoji": {
          "type": "kuromoji_tokenizer"
        }
      },
      "analyzer": {
        "kuromoji_analyzer": {
          "type": "custom",
          "tokenizer": "kuromoji_tokenizer",
          "filter": [
            "kuromoji_baseform",
            "pos_filter",
            "greek_lowercase_filter",
            "cjk_width"
          ]
        }
      }
    }
  },
  "mappings": {
    "post": {
      "_source": {
        "enabled": true
      },
      "_all": {
        "enabled": true,
        "analyzer": "kuromoji_analyzer"
      },
      "properties": {
        "id": {
          "type": "integer",
          "index": "not_analyzed"
        },
        "name": {
            "type": "string",
            "index": "not_analyzed"
        },
        "text": {
          "type": "string",
          "index": "analyzed",
          "analyzer": "kuromoji_analyzer"
        }
      }
    }
  }
}

上半分がAnalyzer、下半分がMappingの設定。
これをanalyzer.jsonというファイルにしてElasticsearchにPUT。

$ curl -XPUT localhost:9200/post-demo --data-binary @analyze.json

5. Elasticsearchにデータを投入

設定したMappingに合わせてデータをjson形式にしてPOSTする。

{"index": {"_id": 1, "_type": "post", "_index": "post-demo"}}
{"id": 1, "name": "user1", "text": "今日の天気は曇だった。"}
{"index": {"_id": 2, "_type": "post", "_index": "post-demo"}}
{"id": 2, "name": "user2", "text": "今日は昨日に比べて暖かかった。"}
{"index": {"_id": 3, "_type": "post", "_index": "post-demo"}}
{"id": 3, "name": "user1", "text": "まさかの大雨。昨日洗濯しておくべきだった。"}

今回はこれをdata.jsonというファイルにしておき、ElasticsearchにPOST。

$ curl -XPOST localhost:9200/_bulk --data-binary @data.json

念のため、GETでデータが正しく投入されていることを確認。

$ curl -XGET localhost:9200/post-demo/post/_search -d '{"query":{"match":{"text":"天気"}}}'

6. Kibanaのダウンロードと起動

こちらからkibanaをダウンロードしてくる。
※ kibana 4.2.0以降はelasticsearch 2.0.0以降でないと動作しませんでした。今回elasticsearch 1.7.3を使用しているので、kibana 4.1.2をここから落としてきて使用します。

ダウンロードしてきて中身を取り出せたら、kibanaを起動します。

$ [kibanaのホーム]/bin/kibana

7. kibanaの設定

(http://localhost:5601/)へアクセスし、「index name or pattern」に作成したインデックス名(今回はpost-demo)を入れる。また、今回は「Index contains time-based events 」のチェックを外しておく。

8. kibanaでグラフを表示する

メニューバーの「Visualize」から好きなグラフの形を選択、X軸・Y軸それぞれの要素を決定してグラフを表示。

最後に

後半がテキトウになった感は否めない。

Groongaを使ってみたら意外と簡単だった

プログラミング

お仕事の関係で全文検索エンジンを色々調べてます。
今日は、Groongaを使ってみました。

これは...いいものだ...

という感じでした。

インストール等々については環境によって異なりますので、公式サイトを確認してください。

http://groonga.org/groonga.org

データベースを作る

$ groonga -n /tmp/shop.db

データベースにアクセス

$ groonga /tmp/shop.db

>

テーブルを作る

> table_create --name Product --flags TABLE_HASH_KEY --key_type UInt32

nameオプションはテーブル名、key_typeオプションは主キーの型を指定します。

テーブルにカラムを追加

> column_create --table Product --name title --type ShortText

tableオプションはカラムを追加するテーブル名、nameオプションは追加するカラム名typeオプションは追加するカラムが管理するデータの型を指定します。

レコードをロード

レコードの挿入と更新を同時にやってくれます。

> load --table Product
[
{"_key":1, "title":"product1"},
{"_key":2, "title":"product2"}
]

tableオプションにレコードをロードするテーブル名を指定する。挿入するレコードはjson形式で記述します。

レコードの取得

> select --table Product --query _key:1
[[0,1445353434.28678,0.00111794471740723],[[[1],[["_id","UInt32"],["_key","UInt32"],["title","ShortText"]],[1,1,"product1"]]]]

tableオプションに対象のテーブルを指定します。queryオプションに取得してくるレコードの条件を記述します。SQLと同じように色々指定できますので、公式ドキュメントを参考にしてみてください。

全文検索用語彙表の作成

Groongaは全文検索エンジンなので、語彙表を作っておけばselectコマンドで全文検索できます。
今回はProductテーブルのtitleカラムを全文検索対象にしてみます。

> table_create --name Terms --flags TABLE_PAT_KEY --key_type ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto

ここまほぼおまじないです。
詳しくは公式ドキュメントを参照してくだされ。

全文検索用のインデックスカラムの作成

> column_create --table Terms --name product_title --flags COLUMN_INDEX|WITH_POSITION --type Product --source title

全文検索用のカラムなので、先ほどのTermsテーブルに対してカラム追加します。
nameオプションは追加するカラム名typeオプションはインデックス対象になるテーブル名、sourceオプションはインデックスの対象になるカラム名を指定します。flagsオプションは...とりあえずはじめはおまじないということで。

全文検索

先ほど登録したインデックスを使って全文検索してみます。

> select --table Product --query title:@Product
[[[2],[["_id","UInt32"],["_key","UInt32"],["title","ShortText"]],[1,1,"product1"],[2,2,"product2"]]]]

selectコマンドのqueryオプションで先ほどのインデックスに対応したカラムを指定します。このとき、「@」をつけることで、全文検索することができます。

また、以下のように実行しても同じ結果になります。

> select --table Product --match_columns title --query product
[[[2],[["_id","UInt32"],["_key","UInt32"],["title","ShortText"]],[1,1,"product1"],[2,2,"product2"]]]]

以上です。
ね、簡単でしょ??

オンライン手書き数字識別システムを作りました。

プログラミング

オンラインで動作する手書き文字識別システムを実装・公開しました。
以下で試すことができます。(黒色のキャンバス部分に数字を1文字を書いて、識別ボタンを押してみてください。)

Flask Canvas

ソースコードは、

github.com

言語はPython 3.4.3を使用、Webアプリ周りはflask、識別器はchainerを使ってディープラーニングモデルを構築しました。
仕組みとしては、

  1. HTML上のCanvasに書かれたものを画像としてアプリにPost
  2. アプリ側で学習済みティープラーニングモデルを使って画像に書かれたものを識別
  3. 識別結果を返却、画面上に表示

という流れです。

ディープラーニングモデルについては、こちらのサイトを参考にさせていただいた。(いつも読ませていただいております。)
MNISTデータを学習後モデルを書き出して、ここで作成したモデルをアプリ側でpickleをつかって読み込んでいます。
おかげさまで、識別器の実装はかなり簡単でした。

問題だったのは、「Canvasに書かれた要素を画像としてアプリで受け取って学習器に渡す」というところ。
そもそもflaskの文献が少ない上に、今回は実行環境の関係で普段使っているOpenCVではなくPillowで画像処理を実装したので結構苦労しました。
最終的に、Postされた画像データはbyte形式で送られてきていることをがわかったので、それをPillowにうまく食わせて処理するようにしたらなんとか実装できました。。

とりあえず、今回は「こんなん実装したで(ドヤァ」という報告だけ。
細かい技術的なことはまた次回。

flask + jQueryでajax通信してみた。

プログラミング

ここ数日、flaskしか書いてない。

今回は、jQueryでflaskに対してpostを投げて、帰ってきた結果を画面上に表示させるということをやってみます。
一応、ajax通信です。

コード全体は、ここにおいてます。

github.com

動作としては、

  1. 画面上のボタンを押して、flaskに対してpostリクエストを投げる
  2. flaskがpostリクエストに対して結果を返却
  3. 結果を受け取って画面上のspanタグに書き込み

という流れになります。

1. scriptの設定

htmlのbodyにボタンを配置して、押された時の動作をscriptに書きます。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$(function() {
    $('#send').click(function() {
        $('#result').text("");

        $.ajax({
            type: "POST",
            url: '/post',
            dataType: 'json',
            processData : false,
            contentType : false,
            success: function(result) {
                console.dir(result);
                $('#result').text(result.message);
            },
            error: function() {
                console.dir("error");
            }
        });
    });
});
</script>

上はjQueryのインポート。下がボタンをおした時の動作。
ボタンには#sendをidとして設定しているので、click()としてクリックされた時の動作を設定します。はじめにspanタグ内の文字列を念のため消しておきます。
その後はajax通信をするための設定です。postを投げたいので「type: "POST"」とします。送り先は「url: '/post'」です。このurlはflaskの中のルートの設定で決まります。通信の結果はjsonを送るので「dataType: 'json'」。 processDataとcontentTypeについては今回は使用しないのでfalseに。「success / error」は通信が正常に終了したかどうかです。どちらもとりあえずコンソールログに出力しておいて、通信が成功した時だけ、結果を画面上に表示させます。

この辺りはajaxをするときの設定なので、flask関係ないです。

2. flaskの設定

といっても、flaskとしては正しくルートを設定しておいて結果を返却するだけ。
今回はjsonで結果を返すようにしたかったので、該当のメソッドの実装は

@app.route('/post', methods=['POST'])
def post():
    return json.dumps({"message" : "通信成功!!"})

としました。普通だな!!

以上で完成です。
あとはpython app.pyとしてサーバーを起動、ブラウザからアクセスして動作確認してみましょう。

簡単にwebアプリが書けるflaskを試してみた。

プログラミング

週末にflaskをいじってました。
いやぁ、簡単!

まず、flaskをインストール。

$ pip install flask

次に以下のような実装を書いて、

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

pythonで起動。

$ python app.py

これで、アプリが立ち上がる。 あとは、好きな処理を書いていくだけ。
ね、簡単でしょ?


2015年10月16日 タイトル修正

ごちうさ1期OP白黒動画をアップロードしました。

プログラミング

ごちうさ2期放送開始記念ということで(こじつけ)、1期のOPを白黒の動画にしてニコニコ動画にアップロードしました。

www.nicovideo.jp

ここでは動画の内容よりも、作った際の作業手順のメモ。
使ったツールは、以下のとおり。

ffmpeg : 動画→静止画、静止画→動画の変換
python + opencv : 静止画を白黒に変換

また、作業するフォルダの構成は以下の様なものを想定しています。

workspace : 作業フォルダ
workspace/images : 切り出した静止画を入れるフォルダ
workspace/script.py : 静止画を白黒画像に変換するpythonスクリプト
workspace/op.mv4 : 元になる動画

まずは、元になる動画を見つけてきます。
これは自力でなんとかしてください。

続いて、取ってきた動画を連続した静止画に切り出します。

$ ffmpeg -i op.mv4 -f image2 images/%06d.jpg

これで、op.mv4から切り出した静止画をimagesフォルダに入れます。

静止画を白黒画像に変換するpythonスクリプトですが、今回は次のように実装しました。

import cv2
import glob

# 画像のファイルパスを取得
paths = glob.glob('images/*')

for index,path in enumerate(paths):
    # 画像をグレースケースで読み込む
    image = cv2.imread(path, 0)
    # グレースケースになった画像を白黒画像として抽出
    ret, th = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU )

    # 抽出した画像を保存
    cv2.imwrite('images/%06d.jpg' % index, image)

OpenCVで読み込んだ画像を白黒に変換して保存し直します。
今回はリサイズなどもしていないので、スクリプト自体は簡単に実装しています。

あとは、これを実行します。

$ python scripy.py

最後に変換した画像をつなげて、一本の動画にします。

$ ffmpeg -f image2 -i images/%06d.jpg op.mp4

以上です。 ね、簡単でしょ??今回は必要な部分しか説明していませんが、ffmpegOpenCVも動画像を扱うことのできるかなりリッチなツールです。
みなさんもドゥンドゥン活用してみてください!

anaconda3にOpenCV3をインストールする

プログラミング

インストールできたので手順メモ。
anaconda2系のインストール手順はすぐ見つかるけど、anaconda3系のインストール手順が見つからなかった。anaconda3に対してconda installでopencvを入れようとしたところ、

$ conda install -c https://conda.binstar.org/jjhelmus opencv

...

Hint: the following packages conflict with each other:
  - opencv
  - python 3.4*

と言われてインストールできなかった。

ただ、そういえば最近OpenCV3がリリースされてたことを思い出し、binstar search -t conda opencv3で検索するとOpenCV3のパッケージがconda installできることがわかった。
OpenCV3はpython3にもちゃんと対応していたはずなので、インストールして使ってみたらちゃんと動いた。

## anacondaにopencv3をインストール
$ conda install -c https://conda.binstar.org/menpo opencv3

あとは、import cv2すればOpenCVと同じように使えます。