簡単な使い方
ブログのエントリを検索する例により使い方を説明します。
ここでの説明で使用するプログラムや設定ファイルはexampleディレクトリにありますので、あわせて参照ください。
文書のスキーマ定義
今回検索したいブログデータには以下の属性があります。
Luxでは、このような属性値を文書のスキーマとして定義する必要があります。
以下に定義例を示します。(blogs.document.conf)
field {
name: "title"
index {
indexing: true
index_to: "default"
}
display: true
}
field {
name: "url"
display: true
}
field {
name: "created_at"
display: true
attr_index {
indexing: true
type: STRING
size: 15
}
}
この文書定義ファイルでは、この文書には3つの属性(field) title、url、created_at があり、field {} でそれを表しています。
そして、各fieldの中に、それぞれの属性の詳細を書きます。
fieldの中には、name, index, display, attr_index などを書くことができ、それぞれの意味は以下の通りとなります。
- name: 属性値の名前(任意の文字列が可)
- index: インデックスの設定
- indexing: インデックスに追加するかどうか (true/false - デフォルトはfalse)
- index_to: この属性をどのインデックスに追加するか (任意の文字列を指定可 - デフォルトは"default")
- display: 表示用に使用するかどうか (true/false)
- attr_index: 属性インデックス(ソート用属性)の設定
- indexing: インデックスに追加するかどうか (true/false - デフォルトはfalse)
- type: この属性のタイプ (STRING/INT)
- size: この属性をサイズ
上記のスキーマでは、
- titleを"default"というインデックスに追加し、表示用にも使用する
- urlを表示用にのみ使用する
- created_atを表示用に使用し、文字列の属性インデックスに追加する
という定義になります。
文書の追加プログラム
上記で定義した文書スキーマをもとに、ブログのエントリデータを追加するプログラムを以下に示します。
#include <lux/index.h>
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
//エントリID^X投稿日^XURL^Xタイトル
int main(int argc, char *argv[])
{
if (argc != 2) {
std::cerr << argv[0] << " service" << std::endl;
exit(1);
}
Lux::Config::Document doc_config;
if (!Lux::DocumentConfigParser::parse(argv[1], doc_config)) {
std::cerr << "parse failed." << std::endl;
exit(1);
}
// create indexer
Lux::Engine engine(doc_config);
if (!engine.open(argv[1], Lux::DB_CREAT)) {
std::cerr << "opening engine failed" << std::endl;
exit(-1);
}
Lux::Indexer indexer(engine);
// for each document to be indexed
int i = 0;
std::string line;
while (getline(std::cin, line)) {
std::vector<std::string> items;
boost::split(items, line, boost::is_any_of("^X"));
// invalid input
if (items.size() != 4) { continue; }
// create a document and add a title field object to it
Lux::Document *doc = new Lux::Document(items[0]);
doc->add(Lux::Field::create("created_at", items[1]));
doc->add(Lux::Field::create("url", items[2]));
doc->add(Lux::Field::create("title", items[3]));
// add the created document to index
indexer.add(doc);
std::cout << ++i << ": " << items[0] << " indexed." << std::endl;
delete doc;
}
return 0;
}
索引構築の流れは、
- 15,16行目: 先ほど作成した文書の定義ファイルを読み込む
- 22,23行目: インデクサをインスタンス化
- 32-50行目: 各ブログエントリを追加するループ
- 41-47行目: 文書インスタンスを作成し、インデクサに追加することで、検索インデックスを更新
となります。
文書の検索プログラム
上記で定義した文書スキーマをもとに、ブログのエントリデータを検索するプログラムを以下に示します。
#include <lux/search.h>
#include <iostream>
#include <string>
#include <time.h>
#include <sys/time.h>
double gettimeofday_sec()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + (double)tv.tv_usec*1e-6;
}
int main(int argc, char *argv[])
{
if (argc < 3) {
std::cerr << argv[0] << " service query" << std::endl;
exit(1);
}
double t1, t2;
t1 = gettimeofday_sec();
Lux::Config::Document doc_config;
Lux::DocumentConfigParser::parse(argv[1], doc_config);
// create search condition
Lux::SortCondition scond(Lux::SORT_SCORE, Lux::DESC);
//Lux::SortCondition scond(Lux::SORT_ATTR_STR, Lux::DESC, "created_at");
Lux::Paging paging(5);
Lux::Condition cond(scond, paging);
// search for the query
Lux::Engine engine(doc_config);
if (!engine.open(argv[1], Lux::DB_RDONLY)) {
std::cerr << "engine.open failed" << std::endl;
exit(-1);
}
Lux::Searcher searcher(engine);
Lux::ResultSet rs = searcher.search(argv[2], cond);
t2 = gettimeofday_sec();
// for each search result
std::cout << "total hits: " << rs.get_total_num() << std::endl;
std::cout << "base: " << rs.get_base() << std::endl;
std::cout << "num: " << rs.get_num() << std::endl;
std::cout << "time: " << t2 - t1 << std::endl;
rs.init_iter();
while (rs.has_next()) {
Lux::Result r = rs.get_next();
std::cout << "[id] " << r.get_id() << std::endl;
std::cout << "[title] " << r.get("title") << std::endl;
std::cout << "[created_at] " << r.get("created_at") << std::endl;
std::cout << "[url] " << r.get("url") << std::endl;
std::cout << "score: " << r.get_score() << std::endl;
std::cout << std::endl;
}
return 0;
}
検索の流れは、
- 24,25行目: 索引構築の場合と同様に、文書の定義ファイルを読み込む
- 28-31行目: 検索条件を指定
- 34-39行目: サーチャをインスタンス化(読み取りのみで)
- 41行目: 検索処理(結果をResultSetで受け取る)
- 49-58行目: 結果の取得(ResultSetのイテレータから取り出し)
となります。
コンパイル & 実行
コンパイル
$ cd example
$ make
$ (index, search が作成される)
索引構築
$ ./index blogs < posts
$ (第一引数の"blogs"は設定ファイルの"xxx.document.conf" の部分を指定
検索
$ ./search blogs live
$ (結果)
ここまでがLuxでの検索までの流れになります。