HeliosearchのNativeライブラリの使い方

初めまして。海老澤と申します。

先日第15回Solr勉強会で発表させて頂いたHeliosearchについて
せっかくなので、自分が詰まったところ、Nativeライブラリ周りについて
メモを残しておきたいと思います。

実施するべきことは

(1) Nativeライブラリのコンパイル
(2) NativeライブラリをHeliosearchの実行パスに通す
(3) Heliosearchの起動

の３点となります。

--------

# (1) Nativeライブラリのコンパイル

まず、ライブラリをコンパイルしてみましょう。
ソースコードは、Heliosearchをgit cloneなりアーカイブの解凍なりして落としてきたら
以下のディレクトリにあります。

heliosearch/solr/native/
　_test_perf.sh
　docset.cpp
　docset.h
　facet.cpp
　HS.cpp
　HS.h
　make.sh
　test.cpp

思ったより少ないですね。
テスト用ファイルを除けばcppはたった3ファイルです。

では、早速コンパイルを……というわけにはいきません。
なぜならば、JNI経由で呼び出すコードであるため
javahを作る都合上、コンパイル済みのJavaクラスファイルが必要であるためです。

というわけで、まずはHeliosearchのJavaビルドをしてみましょう。
ビルド手順はSolrと同じでantから実行すればOKです。
なお、成果物となるライブラリの名前がSolrと全く同じなため、環境を分ける場合は混ざらないようお気をつけ下さい。


ビルドが終わったら、いよいよNativeライブラリのコンパイルに行きたい。

が、そうは問屋がおろしません。
すいません、私のせいではないので怒らないで下さい……。

まず、あなたがHeliosearchを使いたい環境は何でしょうか？
Windows？Linux？はたまたMac？？

Macの方すみません。試せる環境がないので試したことがないのですが
きっと出来るはずなので、ぜひ試してレポを上げて頂ければと思います。

というのも、nativeフォルダ内にある"make.sh"が鍵となっています。
ただのシェルスクリプトなのでテキストエディタ等で開いてみてください。
こんな感じの分岐があります。

```make.sh
OS=`uname`
case $OS in
  Darwin)
    ...
  Linux)
    ...
  CYGWIN*)
    ...
  *)
    echo "Unknown OS $OS"
    exit 1
```

以上のOSしか対応しておりません。
Javaと違ってNativeライブラリなので、各環境依存コードを作る必要があるため、仕方ないですね。

ちなみにもう１個罠がありまして、デフォルトでは64bit版しか対応していません。
なのでCygwinでビルドする方は、64bit版Windowsを使用する必要があります。

さらにもう１つ(何個目だ……)の注意点としては
Heliosearchがデフォルトで環境依存のビルドオプションを指定していることがあります。

```make.sh
OPT="-m64 -mtune=corei7 -O6 -msse -msse2 -msse3 -mfpmath=sse"
```
"-mtune=corei7"で思いっきり固定となっているため
もしビルドするマシンがCorei7でないなら対象を変更するか
思い切ってオプションを外してしまいましょう。

ここまで準備が出来たら、"make.sh"を叩けばライブラリが生成されます。
ちなみに成果物もビルドする環境によって変わります。

　Windows：libHS_Windows.so
　Linux：libHS_Linux.so
　Mac：libMac_Linux.so

これらの名前は、Heliosearch起動時に環境変数から取得したOS情報を元に
参照ファイル名が決まるため、メイク環境と実行環境のOSは同じであることが前提となっています。

--------

# (2) NativeライブラリをHeliosearchの実行パスに通す

作成したNativeライブラリを、Solr環境下で参照できる位置に配置します。
パスを通す都合上、実行環境から参照できる位置ならどこでも良いのですが
デフォルトでは、ビルドしたライブラリは"$SOLR/example/native/"にコピーされるため
基本的にはそれに習うといいでしょう。
各運用環境によって異なるかもしれないですが、以下のような配置となります。

```
/solr
  /conf
  /data
  /lib
　
  ...  

  /native
    /libHS_Linux.so ★ここに置く
```

次に、Heliosearch起動時のJVM起動引数にパスを追加します。

```
'-Dsolr.dir="Solr実行環境(先ほど作成したnativeディレクトリの親ディレクトリパス)"
```

ややこしいのですが、こういう指定をする理由はソースファイルにあります。

```HS.java
  static {

    String OS_Name = System.getProperty("os.name");
    // chop at first space
    int idx = OS_Name.indexOf(' ');
    if (idx > 0) {
      OS_Name = OS_Name.substring(0, idx);
    }

    String libName = "libHS_" + OS_Name + ".so";
    String cwd = System.getProperty("user.dir");
    String solrDir = System.getProperty("solr.dir"); // set by command-line ant tests to use solr/example/native

    try {
      boolean found = false;
      File file;

      if (!found && solrDir != null) {
        file = new File(solrDir + File.separator + "native" + File.separator + libName);
        if (file.exists()) {
          found = true;
          System.load(file.getAbsolutePath());
        }
      }

    ......
```

staticブロックの定義であり、初めてHeliosearchが実行された時にロードされる処理です。
System.getProperty()で環境変数を取ってきて、後ろに"/native"をくっつけたファイル名をロードしにいきます。
ちなみにロード処理は失敗したら最大4回分のディレクトリサーチが行われます。
難しいコードではないので、詳しくはソースコードを見てみて下さい。

--------

# (3) Heliosearchの起動

パスが通せたら起動してみましょう。
なお、Heliosearchは「Nativeライブラリが無くても」起動できます！
Nativeライブラリを使う処理のところで、NativeコードをロードできずにExceptionが発生するだけです。

そのため、ちゃんとNativeライブラリがロードできているかはログを見ましょう。
無事ロードできていれば以下の様なログが出ます。

```
!!!!!! Heliosearch native libraries loaded. !!!!!!
```

このログは、Nativeライブラリ内でstdoutに出力されています。
筆者の環境ではTomcat上でHeliosearchを動作させており
catalina.outに出力されていました。

もしNativeライブラリをロードしにいって失敗した場合は
何らかのExceptionが出ているはずなので見直してみましょう。

--------

長々とお付き合い頂きありがとうございました。
HeliosearchはSolrと比べて異色な処理が増えていますが
検索エンジンとしての本質は変わっていませんので
ぜひこの機会に色々触って、試してみてください。

それでは、またの機会に。