GitBucketで高速に横断検索するためのプラグイン

この記事では、GitBucketの検索機能を強化するプラグイン[gitbucket-fess-plugin](https://github.com/codelibs/gitbucket-fess-plugin/)について紹介します。

このプラグインは、GitBucketと、[全文検索サーバー Fess](https://github.com/codelibs/fess/)を連携させることによって、

* 複数のリポジトリ間を**横断する検索**を
* **高速に**

行えるようにします。
以降、今回紹介するプラグインのことを**Fessプラグイン**と呼びます。

これはFessプラグインを使用した際のGitBucketのスクリーンショットです。
"code"という文字列を含むソースコードを、複数のリポジトリを対象に検索できていることが分かると思います。
![search_screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/51175/e4984e81-6cb5-1dd1-6178-8b1219ba465f.png)

FessプラグインはGitHub上で公開しています。

[GitHub - codelibs/gitbucket-fess-plugin](https://github.com/codelibs/gitbucket-fess-plugin/)

(**追記 2017/3/20:** 記事執筆時はβ版でしたが、このたびバージョン1.0.0をリリースしました! )

この記事では、まず、プラグインの概要を紹介し、その後で導入手順について、説明します。

---

この記事は [Fess Advent Calendar 2016](http://qiita.com/advent-calendar/2016/fess)の25日目の記事です。
24日目は「[Docker上でElasticsearchのデータをNamed Data Volumeに保存しFessで利用する](http://qiita.com/cookienote/items/03c7502e5dc553289614)」でした。

# GitBucketとは？
[GitBucket](https://github.com/gitbucket/gitbucket)は、オープンソースのGitサーバーです。
コマンド一つで、GitHubのようなGitサーバーを簡単に立てることができます。
issueやpull requestのような機能も開発を便利にする機能もサポートされています。プラグインによる拡張もしやすいことも大きな特徴です。
また、開発者が日本の方ということもあって、[Gitter](https://gitter.im/gitbucket/gitbucket_ja)などにて、日本語での質問がしやすいという利点もあります。
個人的にはScalaで実装されていて、読みやすいというのも長所だと思っています。

# GitBucketのデフォルトの検索機能
GitBucketにはデフォルトで、レポジトリ内のコード、issue、wikiを検索する機能を持っています。
ただし、その検索機能には、次のような弱点があります。

* 多くのファイルを含むリポジトリを検索したとき、レスポンスが**遅い**
* 検索対象が**一つのリポジトリに限定**されている

レスポンスが遅いのは、検索の度に全ファイルを走査してしまっているのが原因です。
リポジトリに含まれるファイルが少ない場合は良いのですが、多くのファイルを含むリポジトリを検索しようとすると検索結果ページの表示に体感でわかるほど時間がかかってしまいます。

# Fessプラグイン
検索速度の問題を解決するには、事前にリポジトリをクロールして、インデックスに登録しておくということが必須です。
実際、GitHubでのソースコード検索もそのようなことをしています。

前置きが長くなりましたが、GitBucketでそのような高速な検索を実現しようと開発しているのが、この記事のテーマである[**Fessプラグイン**](https://github.com/codelibs/gitbucket-fess-plugin/)というわけです。
このプラグインでは、「クロールし、インデックス登録をする」・「検索クエリに対してレスポンスを返す」という部分を、オープンソースの全文検索サーバーである[Fess](https://github.com/codelibs/fess/)と連携することで実現します。

Fessは **「5 分で簡単に構築可能な全文検索サーバー」** です。
ざっくりいうと、自分でクローラを設定して、自分だけの検索エンジンがつくれるソフトウェアというようなイメージです。
とりあえず、Fess自体の雰囲気をつかむならば、こちらの[**デモページ**](http://search.n2sm.co.jp/)を見ていただけたらと思います。
より詳しい説明は、[公式ドキュメント](http://fess.codelibs.org/ja/)や[このスライド](http://www.slideshare.net/shinsuke/fess-69788304)がわかりやすいと思います。

Fessは内部で[Elasticsearch](https://www.elastic.co/jp/products/elasticsearch)を利用することで、高速で高精度な検索を実現しています。

## Fess プラグインの仕組み

さて、全体の構成は図にするとこんな感じになります。

![qiita_ja_small.png](https://qiita-image-store.s3.amazonaws.com/0/51175/3ccfa9ae-c119-4961-ce3e-4c6b4c488567.png)

FessはGitBucketのリポジトリの中身をAPIを通じて、定期的にクロールし、インデックス登録しています。
一方、ユーザーが検索をする場合は、プラグインを通じてFessに検索クエリが投げられ、その結果返ってきた結果が表示されます。
よって、Fessプラグインが提供するのは、Fessとの連携部分と 横断検索用のユーザーインターフェイス部分ということになってます。

# Fessプラグインの導入手順
それではFessプラグインを、GitBucketに導入するための手順を説明していきます。
(日本語ドキュメントのようなつもりで丁寧めに書いたら長くなってしまったので、とりあえずは斜め読みしていただいても結構です。)

導入の流れは次のようになります。

1. プラグインのダウンロード
2. GitBucket・Fessの起動
3. リポジトリアクセスのためのトークンを発行 **[GitBucket側]**
4. クローラの設定・実行**[Fess側]**
5. 検索のためのトークンを発行 **[Fess側]**
6. Fessの情報を登録 **[GitBucket側]**

GitBucketとFessの間で双方向にやりとりをすることになるため、お互いにアクセストークンを発行しあう必要があり、若干面倒ではありますが、一度設定してしまえば、その後ユーザーは特に何もしなくてもFessによる検索機能が使えるようになります。

以降、スクリーンショットを交えながら、順に説明していきます。

## 1. プラグインのダウンロード
[Fessプラグインの](https://github.com/codelibs/gitbucket-fess-plugin/)のREADME中のリンクから、jarファイルをダウンロードしてきます。
落としてきたjarファイルは `~/.gitbucket/plugins/` 以下に保存してください。(そのようなディレクトリがない場合は作ってください。)

## 2. GitBucket・Fessの起動
GitBucketとFessを起動します。
それぞれのREADMEに従えば、どちらもコマンド一つか二つくらいで起動できます。

* [GitBucket](github.com/gitbucket/gitbucket)
* [Fess](https://github.com/codelibs/fess)

この時、ポート番号が衝突しないように注意してください。
GitBucket・Fessともにデフォルトで `http://localhost:8080/` に立ちます。
これを回避するには、例えば、GitBucketを起動する際に、
`$ java -jar gitbucket.war --port=8888`
というような感じで、ポート番号を指定してやればよいです。

**追記 2017/3/20:**
ポート番号による区別だけだと、ブラウザでのセッション管理がうまくいかないのか(?)、勝手にログアウトされてしまうことがあるので、
パスも指定した方が良いです。
例:
**GitBucket: `http://localhost:8080/gitbucket/`**
`$ java -jar gitbucket.war --port=8080 --prefix=gitbucket`

**Fess: `http://localhost:8081/fess/`**
`$ ./bin/fess -Dfess.port=8081 -Dfess.context.path=/fess/`


## 3. リポジトリアクセスのためのトークンを発行 **[GitBucket側]**
FessがGitBucketのリポジトリにアクセスできるようにするために、GitBucket側でアクセストークンを発行します。

GitBucketにログイン後、右上のユーザーアイコンから `Account settings`に遷移後、サイドバーから`Applications` を選ぶことで、トークンの発行画面にたどり着けます。

## 4. クローラの設定・実行**[Fess側]**
3.で発行したトークンを使って、クローラを設定します。

### 4-1. クローラの設定
Fessの管理画面に入り、`クローラ > データストア` と移動し、GitBucketをクロールするための設定をします。
公式ドキュメントの[このページ](http://fess.codelibs.org/ja/10.3/admin/dataconfig-guide.html)も参考にしてください。

この画面において設定の必要があるのは、

* 名前
* ハンドラ
* パラメータ

の3項目です。
「名前」には好きな文字列を入力してください。「ハンドラ名」は`GitBucketDataStore`を選択してください。
「パラメータ」には、GitBucketのURLと、2で発行したトークンを以下のフォーマットで入力してください。(`[`と`]`は含みません。)

```
url=[GitBucketのURL]
token=[2で発行したトークン]
```

その他のフォームはそのままで大丈夫です。
こんな感じになります。(パラメータ中のトークンはダミーです。)
![dataconfig.png](https://qiita-image-store.s3.amazonaws.com/0/51175/ad0f9a21-b325-6b14-3449-7b3ef624a8b5.png)
そうしたら、ページ下部の「作成」ボタンを押すことで、クローラの設定の作成を完了してください。
「データストアのクロール」の一覧に遷移し、作成した設定が追加されているはずです。

### 4-2. ジョブスケジューラの作成
さて、次は実際のクロールジョブスケジューラを作成しましょう。
一覧から今作った設定を選択すると、こんな画面に遷移するので、下部の「新しいジョブの作成」を押してください。
![dataconfig_detail.png](https://qiita-image-store.s3.amazonaws.com/0/51175/f4fe2bfa-2d6e-697a-5921-d024b87ba9c1.png)

すると、ジョブスケジューラの設定フォームに移るはずです。
「スケジュール」フォームにパラメータをいれることで、[定期的にクロールするように設定](http://fess.codelibs.org/ja/10.3/admin/scheduler-guide.html#id9)できたりしますが、この設定は後からでも変更できるので、とりあえず試すだけならば、この画面では何も変更をせずに作成ボタンを押して大丈夫です。
詳しくは、[このページ](http://fess.codelibs.org/ja/10.3/admin/scheduler-guide.html#id5)を参考にしてください。

### 4-3. クローラの実行
ジョブスケジューラの一覧ページに遷移し、リストの一番上に今作ったクローラが表示されていると思います。
それをクリックしたあと、「今すぐ実行」を押してください。
画像のように、状態が「実行中」になればクロール開始に成功です。
![jobs.png](https://qiita-image-store.s3.amazonaws.com/0/51175/ed522bfb-0af4-5967-26b9-65aa066ef9c5.png)
クロールにはしばらくかかるので、待ちます。状態が「実行中」から「有効」になったら、クロール終了です。

### 4-4. 検索のテスト
クロールが終了したら、管理画面の左上の検索フォームから、検索してみてください。
検索結果にGitBucketに保存されているファイルがでてきたら、うまくクロールできた証拠です。
これで、Fessから、GitBucketの内容を検索できるようになったわけです。

## 5. 検索のためのトークンを発行 **[Fess側]**
あとは、GitBucketから、Fessの検索結果を取得できるようにすれば、OKです。
そのために、Fessの検索結果へアクセスするためのトークンを発行します。

アクセストークンは、Fessの管理画面のサイドバーから、`システム > アクセストークン` と遷移することで発行できます。
公式ドキュメントでは[このページ](http://fess.codelibs.org/ja/10.3/admin/accesstoken-guide.html)に対応します。


## 6. Fessの情報を登録 **[GitBucket側]**
これがラストステップです。Fess側で発行したアクセストークンをGitBucket側に登録します。
管理者としてGitBucketにログイン後、 `http://[GitBucketのURL]/fess/settings` にアクセスすると、画像のようなフォームが現れます。
![fess-settings.png](https://qiita-image-store.s3.amazonaws.com/0/51175/a693e83b-46d9-e858-50f1-e6f9eca263ed.png)

「Fess URL」の欄にFessのURLを、「Access Token」の欄に**5.**で発行したFessのアクセストークンを入力すればOKです。

実は画像の「Access Token」の欄に「Optional」とあるように、Fessのアクセストークンの入力は必須ではありません。ただ、ここでトークンを入力することで、各ユーザーは自分がアクセスできるプライベートリポジトリに対する検索もできるようになります。(もし、トークンを入力しなければ、パブリックリポジトリのみが検索対象になります。)

---

これにて、プラグインの設定はおしまいです。お疲れ様でした。
これで管理者以外のユーザーも、 `http://[GitBucketのURL]/fess` にアクセスすることで、Fessを使ったGitBucketの検索機能を利用することができます。

# 今後の展望
いまのところ、このFessプラグインでは、全てのリポジトリの内容を対象とした検索をサポートしていますが、
今後は**issueやwikiの内容**も検索の対象にしたいと考えています。
[issue取得のAPI追加のPR](https://github.com/gitbucket/gitbucket/pull/1385)をマージしていただいたので、それを使ってやる予定です。
(**追記 2017/3/20:** issue/wiki の検索もサポートしました)


また、横断検索だけでなく、**特定のリポジトリのみを対象とした検索** もFess経由でできたら良いかなとも考えています。
これは現在のGitBucketのデフォルトの検索機能でできますが、Fessを使ったほうが、確実に高速なので。
もし、そこまでできるようになれば、GitBucketの検索機能の**強化**ではなく、**置換**が果たせるのではないかと思ってます。

---

GitBucketユーザーの方は、是非、Fessプラグインを使ってみてください！
何かありましたら、コメントやGitHubの[issue](https://github.com/codelibs/gitbucket-fess-plugin/issues)、または[僕のTwitter](https://twitter.com/kw_udon_)宛にお知らせいただけると幸いです。