簡単な使い方

ブログのエントリを検索する例により使い方を説明します。
ここでの説明で使用するプログラムや設定ファイルは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 などを書くことができ、それぞれの意味は以下の通りとなります。 上記のスキーマでは、 という定義になります。

文書の追加プログラム

上記で定義した文書スキーマをもとに、ブログのエントリデータを追加するプログラムを以下に示します。
#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;
}
索引構築の流れは、 となります。

文書の検索プログラム

上記で定義した文書スキーマをもとに、ブログのエントリデータを検索するプログラムを以下に示します。
#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;
}
検索の流れは、 となります。

コンパイル & 実行

コンパイル
$ cd example
$ make
$ (index, search が作成される)
索引構築
$ ./index blogs < posts
$ (第一引数の"blogs"は設定ファイルの"xxx.document.conf" の部分を指定
検索
$ ./search blogs live
$ (結果)
ここまでがLuxでの検索までの流れになります。