ElasticSearch で文書を検索をしてみる
ElasticSearch
で提供されている代表的な文書の検索機能には、全文検索クエリと Term ベースクエリがあります。全文検索クエリは、検索時のキーワードが含まれているるドキュメントを探し出すための検索クエリです。一方 Term ベースクエリは、検索時のキーワードが完全に一致するドキュメントを探し出すための検索クエリになります。
よくある検索エンジンのようにキーワードが含まれている WEB ページを探すというような用途では全文検索クエリが適していますが、ユニークなキー値のようなものをキーワードにして、そのキー値が割り当てられている文書を探すような用途では Term ベースクエリが適しています。全文検索クエリではあらかじめ文書が単語に分割されて、その単語に対して検索が行われますが、Term ベースクエリでは文書が単語に分割されず、キーワードと完全一致するかで検索されます。ユニークなキー値で検索を行う場合、そのキーワードの一部分ではなくすべてが完全に一致するドキュメントを検索しなければならないので、Term ベースクエリの方が適していることになります。
今日はこの全文検索クエリと Term ベースクエリについて、実際にインデックスを作りながら試していきたいと思います。
検証データを用意する
前提として、今回は以下のインデックスを使うものとします。$ curl -XPUT http://localhost:9200/samurai -H "Content-type: application/json" -d '{
"settings": {
"number_of_replicas": 0,
"number_of_shards": 1,
"analysis": {},
"refresh_interval": "1s"
},
"mappings": {
"_doc": {
"properties": {
"name": {
"type": "keyword"
},
"description": {
"type": "text"
}
}
}
}
}'
このマッピングでは、name
フィールドは keyword
型、description
フィールドは text
型としています。
また、このインデックスには以下のドキュメントを入れておきます。$ curl -XPOST http://localhost:9200/_bulk -H "Content-type: application/json" -d '
{ "index": { "_index": "samurai", "_type": "_doc" } }
{ "name": "真田昌幸", "description": "甲斐国の武田信玄の家臣となり信濃先方衆となった地方領主真田氏の出自で、真田信之、真田幸村の父。" }
{ "index": { "_index": "samurai", "_type": "_doc" } }
{ "name": "真田信之", "description": "真田昌幸の長男。徳川家康の養女を妻としていたため関ヶ原の戦いでは東軍につき、江戸時代には松代藩藩主をつとめた。" }
{ "index": { "_index": "samurai", "_type": "_doc" } }
{ "name": "真田幸村", "description": "真田昌幸の次男。豊臣家臣の大谷吉継の娘を妻としていたため関ヶ原の戦いでは西軍につき、父真田昌幸とともに戦死した。" }
{ "index": { "_index": "samurai", "_type": "_doc" } }
{ "name": "石田三成", "description": "豊臣政権の五奉行の一人。秀吉の死後、徳川家康を倒すため決起するが、関ヶ原の戦いで敗れ、その後処刑された。" }
{ "index": { "_index": "samurai", "_type": "_doc" } }
{ "name": "徳川家康", "description": "豊臣秀吉の天下統一後に台頭した武将で、関ヶ原の戦いに勝利し、江戸幕府を開いた。" }
'
続きを読む
ElasticSearch
コメント (1) 2018/10/10 20:00:43
ElasticSearch 6.4.2 をさわってみた
データを全文検索するためのエンジンである ElasticSearch
を触っていきたいと思います。全文検索というと WEB ページや文書のキーワード検索として広く利用されていますが、最近では RDB への参照性能を改善するため、代替手段として使われる場面も多いようです。RDB から適切なタイミングでデータを同期してやる必要があるものの、複数のテーブルやデータベースから必要なデータのみを集約して参照させるという用途では、RDB よりもはるかに高速にアクセスでき、RDB とは切り離した擬似的な参照系として構築できる点が評価されているようです。
ElasticSearch
も他の分散システムと同じくノードを複数台用意したクラスター構成をとることができますが、今回は手始めということで、シングルノード構成での環境構築からやってみたいと思います。
ElasticSearch をインストールする
公式サイトのダウンロードページから ElasticSearch
の最新版をダウンロードします。現時点での最新版は 6.4.2
でした。Linux 向けには rpm パッケージが公開されていたので、これを使うことにします。
ダウンロードした rpm
パッケージをインストールします。# rpm -ivh elasticsearch-6.4.2.rpm
ElasticSearch
をインストールすると、/etc/elasticsearch/elasticsearch.yml
として設定ファイルが作られます。シングルノード構成の場合には特に elasticsearch.yml
を編集しなくても動くのですが、複数ノード構成でクラスターを組む場合には書き変えてやる必要があります。
インストールした ElasticSearch
は、systemctl start
コマンドから起動できます。
# systemctl start elasticsearch.service
また、自動起動を有効化する場合は systemctl enable
しておきましょう。# systemctl enable elasticsearch.service
続きを読む
ElasticSearch
コメント (0) 2018/10/09 20:05:50
Kafka Manager を構築してみたら Kafka 2.0.0 は対応していなかったお話
Kafka
でクラスター中のノード(Broker
)やパーティション、トピックを WEB ベースで管理するためのツールとして、Kafka Manager
というものがあるそうです。
公式ページである Github リポジトリには、README.md 中に実際の WEB の UI が載っていました。表示されている情報としては、Kafka
にバンドルされている kafka-topics.sh
や kafka-consumer-groups.sh
等から取れるもののようですが、統計的に可視化されていたり、更新処理までできるようです。
Kafka Manager を構築する
公式ページからはバイナリや rpm
パッケージ等は配布されていないようなので、自分でビルドしていきます。
まずは Github
からソースコードを clone
しておきましょう。$ git clone git@github.com:yahoo/kafka-manager.git
ブランチは特に何も考えずに master
を使うことにします。
ソースコードを取得したら、ビルドツールの sbt
からビルドすることができます。$ ./sbt clean dist
ビルドすると target/universal/
ディレクトリ配下に kafka-manager-1.3.3.21.zip
ができあがります。これが Kafka Manager
の実行バイナリを固めた zip
ファイルです。
これを展開すると、bin
ディレクトリ下に kafka-manager
という実行バイナリがあります。これを使うと Kafka Manager
が起動します。$ bin/kafka-manager -Dkafka-manager.zkhosts=localhost:2181 -Dhttp.port=8080
システムプロパティ kafka-manager.zkhosts
には Kafka
の Zookeeper
のホストを指定します。今回は localhsot
で Kafka
クラスターが動いているという前提で、同じマシンの Zookeeper
を指定しました。 http.port
値は Kafka Manager
自体の待受ポートです。8080 ポートを指定しているので、http://localhost:8080 にアクセスすれば Kafka Manager
を使うことができます。
続きを読む
Kafka
コメント (0) 2018/10/05 19:54:32
コマンドラインから Sudachi で形態素解析してみる
日本語を品詞に分割する形態素解析器については、以前試してみた Mecab の他に、最近では Sudachi の評判がよいようです。それならばひとまずは触ってみようということで、今日は Sudachi
をビルドして日本語の文章を形態素解析してみました。
Sudachi をビルドする
Github にてソースコードが公開されているので、 これを clone してきてビルドしてみます。$ git clone git@github.com:WorksApplications/Sudachi.git
$ cd Sudachi
リポジトリには辞書をビルドするためのファイルもコミットされているので、サイズはそれなりに大きいです。lex なので字句解析器ですね。辞書自体は UniDic を使っているようで、ビルド時にダウンロードしている様子がビルドログから伺えます。
Sudachi
は Maven
プロジェクトなので、package
ゴールまで実行すればビルドできます。$ mvn clean package
実際に Sudachi
を動かすにはビルドした jar
ファイルを叩くのですが、そのままビルドしただけではもろもろの設定が足りていません。必要な設定ファイルのサンプルは src/main/resources/sudachi.json、src/main/resources/sudachi_fulldict.json として置かれているので、これをベースに設定をしていきます。
systemDict
値には Sudachi
が利用する辞書のパスを指定します。リポジトリ上では辞書ファイルの名前だけが書かれているので、このパスの辞書にアクセスできるディレクトリで jar
ファイルを実行するか、systemDict
値自体を正しく指定し直す必要があります。
Sudachi
の辞書自体は、ビルドすると target
ディレクトリに system_core.dic
、system_full.dic
として生成されます。また同時に、圧縮された zip
ファイルとしても、sudachi-0.1.1-SNAPSHOT-dictionary-full.zip
、sudachi-0.1.1-SNAPSHOT-dictionary-core.zip
等としてビルドされていました。
ここでは以下の内容の sudachi_fulldict.json
を my_sudachi_config.json
という名前でカレントティディレクトリにコピーし、以下の内容に修正しました。
続きを読む
Sudachi
コメント (0) 2018/10/04 20:41:21
Java から Kafka の Producer を利用してみる
前回 Java で Kafka の Consumer を試してみましたが、今回は Producer を実装してみました。
Consumer 側はパーティション分割された Topic からのメッセージの受け取りでだいぶ詰まっていたのですが、Producer 側はクラスター構成に対してもすんなりと動かせました。実装コードは接続先の Kafka ブローカーの設定値を書き換えるくらいで、同じコードが動いてくれました。
利用したのは前回と同じく Kafka の Java クライアント、kafka-clients
です。dependencies {
...
compile group: 'org.apache.kafka', name: 'kafka-clients', version: '2.0.0'
...
}
Gradle を使う場合、build.gradle
に追加する依存性は前回と同じです。Maven の場合はこの辺りを参考にしてください。
単一ノード構成で Producer を利用する
Producer のサンプルコードは以下の通りです。接続設定をして、Producer のインスタンスを作って、メッセージを送るだけというとてもシンプルな内容になりました。
続きを読む
Kafka
コメント (0) 2018/10/03 19:20:04
Java から Kafka の Consumer を利用してみる
分散メッセージングシステムである Kafka を Java から利用してみました。手始めに今回は Consumer を使い、メッセージの受け取りを試してみることにします。
公式ドキュメントに記載せれている通り、Kafka には Java から接続するためのクライアントライブラリがあります。Maven Central Repository にも公開されているので、Maven や Gradle からすぐに利用することができます。
今回は実際にこの kafka-clients
ライブラリを使って接続してみたのですが、単一ノード構成では問題ないものの、複数ノードでのクラスター構成への接続が一部意図通りに動作してくれませんでした。記事の内容としてはすっきり終わらないものの、現時点でのノウハウとして書いておこうと思います。
kafka-clients をプロジェクトの依存性に追加する
プロジェクト管理には Gradle 4.8.1 を使ってみます。プロジェクトを作ったら、build.gradle
に以下の依存性を追加します。dependencies {
...
compile group: 'org.apache.kafka', name: 'kafka-clients', version: '2.0.0'
...
}
kafka-clients
の現在の最新バージョンは 2.0.0 です。
続きを読む
Kafka
コメント (0) 2018/10/02 19:47:35
chocolablog を ver 0.10 にアップデートしました
ひさしぶりのアップデートです。ver 0.9 のリリースが去年の 11 月なので、もうすぐ 1 年ぶりです。
自分で記事を書いていく中で欲しいなと思った機能を拡張していくことが多くなっていますが、今回も記事を書くための拡張機能をちょこちょこと追加した形になっています。
記事文中のキーワード表記がまさにそれです。こういうやつ
です。マークダウンでインラインコードと呼ばれてるものになります。このブログを始めた頃はただの日記サイトでしたが、最近は技術的な記事の比重が増えているので、記事を読みやすくするための改良が増えていっている気がします。
マークダウンといえば、chocolablog では見出しやスタイルを加えるために独自の chocola 記法というものを実装しているのですが、これも時代の移り変わりに伴って、一般的なマークダウンなんかに変えていったほうがいいのかなと感じています。chocolablog を作り始めた頃は、ドキュメントを記述するための一般的な記述方法みたいなものはありませんでしたが、Github や Qiita がメジャーになっていくにつれて、マークダウン記法がだいぶ浸透してきました。とはいえマークダウンにはマークダウンで方言が乱立しまくっているという現状もあるので、単純にマークダウンに寄せていけばいいのかと言われると微妙なところでもあります。私の中ではっきりとデファクトスタンダードにあわせていこうと決めているわけではないので、ちょっと時間をかけて考えていこうかなといった状況です。
ver 0.10 の追加機能
フロント側
・Scala ソースコード用シンタクスハイライトを追加した
・記事文中のキーワード用の chocola 記法を追加した
システム管理画面側
・記事の公開日時として秒も指定できるようにした
続きを読む
chocolablog 開発
コメント (0) 2018/10/01 19:32:05
Kafka 複数台でクラスターを組んでみる
前回シングルノードでの Kafka 構築を試してみたわけですが、今回は引き続き Kafka 公式ページの Quick Start に従って、Kafka(Broker)複数台でのクラスター構築を試してみたいと思います。
Kafka の Broker が持つデータは Topic 毎にパーティションという単位で分割することができ、そのパーティションを別々の Broker (のプロセスやサーバー)に割り当てたり、コピーを置いておいたりすることで、データ分散による性能改善や冗長化を実現することができます。パーティション内のデータを参照するためのインデックスもパーティション単位で作られるようなので、複数のパーティションにわけておくことで、参照性能をあげられる仕組みになっているようです。分割や複製されたパーティションの管理は Kafka が自動で行ってくれるとのことなので、今回は障害時のフェールオーバーまで試してみたいと思います。
Kafka クラスターを構築する
Broker 2 つで Kafka クラスターを構築してみます。今回は 1 つのマシン内に各 Broker を別プロセスとして用意しようと思います。実際の運用では、サーバーを複数台用意して各マシンで 1 プロセスずつ動かすことになると思いますが、どのマシンで作業するかが変わるだけでやることは同じです。
前提として、Kafka のインストールまでは終わっているものとします。
Broker 毎の設定ファイルとして、server.properties をコピーして server-1.properties と server-2.properties を用意します。# server-1.properties
# Kafka サーバー(Broker)の ID 値
broker.id=1
# Kafka サーバー(Broker)への接続 URI
listeners=PLAINTEXT://localhost:9093
# Kafka サーバー(Broker)の Zookeeper のホスト/ポート
zookeeper.connect=localhost:2181
# Kafka サーバー(Broker)のデータ保存ディレクトリ
log.dirs=/tmp/kafka-logs-1
# server-2.properties
# Kafka サーバー(Broker)の ID 値
broker.id=2
# Kafka サーバー(Broker)への接続 URI
listeners=PLAINTEXT://localhost:9094
# Kafka サーバー(Broker)の Zookeeper のホスト/ポート
zookeeper.connect=localhost:2181
# Kafka サーバー(Broker)のデータ保存ディレクトリ
log.dirs=/tmp/kafka-logs-2
broker.id 値は Broker 毎にユニークである必要があるため、別々の値を設定しています。1 と 2 です。
listeners 値については、今回は同じマシン内の別プロセスとして動かすので、異なるポート番号を指定しました。複数サーバーを用意して 1 サーバー 1 プロセスで動かす構成なら、ポートは同じでもいいと思います。また、ホスト名は localhost からの接続しか試さないので localhost にしていますが、複数サーバーでクラスターを組む場合は localhost 以外から触ることになるでしょうから、各サーバーのホスト名を書くことになると思います。
zookeeper.connect 値も、今回は同じマシン内で動いている Zookeeper を使うので localhost:2181 としていますが、複数サーバー構成でクラスターを組む場合には、Zookeeper の動いているサーバーのホスト名/ポート番号を設定することになるでしょう。
log.dirs 値は、Broker のデータの保存先ディレクトリです。今回は同じマシンで複数プロセスの Broker が動くので、異なるディレクトリを設定しました。複数サーバーを用意して 1 サーバー 1 プロセスで動かす構成なら、同じパスでもいいと思います。
続きを読む
Kafka
コメント (0) 2018/08/27 15:12:18
Kafka を試してみる
Kafka は分散メッセージングシステムです。メッセージを送る Producer、メッセージをためておく Broker、メッセージを受け取る Consumer という構成をとる RabbitMQ や ActiveMQ のようなメッセージングシステムですが、複数のサーバーインスタンスによる分散構成をとれる点も特徴で、特に大量のメッセージを扱うための速度性能、スケーラビリティ、耐障害性などに特化していると言われています。
今回は公式ページのクイックスタートを参考に、Kafka サーバーの構築とメッセージングについて試してみました。
Kafka をインストールする
まず前提として、Java が使えるようインストールしておきます。
java コマンドを叩いて動いていれば大丈夫です。$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
Kafka 公式ページからリンクされているダウンロードページから、Kafka の最新版をダウンロードします。$ wget http://ftp.riken.jp/net/apache/kafka/2.0.0/kafka_2.11-2.0.0.tgz
ダウンロードしたら、アーカイブを展開して適当なディレクトリに置いておきます。$ tar xvfz kafka_2.11-2.0.0.tgz
# mv kafka_2.11-2.0.0 /usr/local/
# ln -s /usr/local/kafka_2.11-2.0.0 /usr/local/kafka
続きを読む
Kafka
コメント (0) 2018/08/16 20:03:53
Flutter ver 0.3.2 の、無限スクロールする GridView のサンプル
『The Infinite ListView』等で Google 検索すると無限スクロールする ListView については情報がえられるのですが、同じようなことを GridView でやっているサンプルは見つからなかったので書いておきます。言うならば、The Infinite GridView のサンプルです。Flutter は ver 0.3.2 を利用しています。 無限スクロールに関しては、やっていることは無限スクロール ListView と同じです。なので GridView のサンプルではありますが、同じ方法論で無限スクロール ListView も作ることができます。
機能としては、以下を実装しています。
・GridView を末尾までスクロールすると、次のデータを新たに作成して追加表示する
・GridView の要素は、表示されるタイミングで構築(遅延構築)される
・GridView の要素は 1 列で 3 個ずつ並べられる
以下がサンプルコードになります。import 'package:flutter/material.dart';
void main() => runApp(new InfiniteGridViewSampleWidget());
/// 無限にスクロールする GridView サンプルの StatefulWidget
class InfiniteGridViewSampleWidget extends StatefulWidget {
@override
InfiniteGridViewSampleState createState() =>
new InfiniteGridViewSampleState();
}
/// 無限にスクロールする GridView サンプルの State
class InfiniteGridViewSampleState extends State<InfiniteGridViewSampleWidget> {
// 表示するデータの List。
// 初期値としてデータを 20 件いれておく。
final List<int> items = new List.generate(20, (index) => index);
// GridView を構築して返す。
// この GridView を末尾までスクロールした場合、表示するデータ件数を増やして追加表示できるようにする。
//
// GridView が末尾までスクロールされたかは、GridView に設定した ScrollController によって検知できる。
//
// GridView に表示される要素の最大数は、GridView が構築された時点で固定される。
// そのため、表示するデータ件数を増やすには、再度 GridView を再構築する必要がある。
@override
Widget build(BuildContext context) {
// GridView のスクロールを検知するための ScrollController。
final ScrollController _scrollController = new ScrollController();
// ScrollController にイベントリスナーを設定する。
_scrollController.addListener(() {
// 最後までスクロールしたら、次のデータを読み込む。
if (_scrollController.position.maxScrollExtent <=
_scrollController.position.pixels) {
// 表示するデータを追加し、ウィジェットを再構築するよう通知する。
setState(() {
// 表示するデータにさらに 20 件データを追加する。
this.items.addAll(
new List.generate(20, (index) => this.items.length + index));
});
}
});
// GridView の要素を表示されるタイミングで構築できるように itemBuilder を指定する。
return new MaterialApp(
home: new Scaffold(
// itemBuilder を指定できる GridView.builder() で GridView を構築する。
body: GridView.builder(
itemBuilder: (BuildContext context, int index) {
// itemBuilder は、引数 index の位置にある GridView の要素が表示されるタイミングで
// 呼び出され、その要素を構築して返す。
print("make item: ${index}");
// 引数 index の位置にある GridView の要素を構築して返す。
return new Center(child: new Text("#${index}"));
},
// GridView で表示するデータの件数を設定する。
// これ以上の件数のデータを表示する場合、新たな itemCount 値を設定して GridView を再構築する必要がある。
itemCount: items.length,
// スクロールされたことを検知するため、ScrollController を設定する。
controller: _scrollController,
// GridView の要素は横に 3 個ずつ並べてレイアウトする。
// これは、new GridView.count(crossAxisCount: 3, children: <Widget>[]) に相当する。
// GridView の要素の配置は SliverGridDelegateWithFixedCrossAxisCount を設定することで指定できる。
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
),
),
);
}
}
続きを読む
Flutter,
Dart
コメント (0) 2018/05/17 19:11:40