MediaWikiを自前で運用している人はCirrusSearchで日本語全文検索を改善しよう

サークルなどで独自にMediaWikiを運用している方向けに、検索を改善するExtensionであるCirrusSearchの導入方法を解説します。

## 背景
### MediaWikiのデフォルト全文検索は日本語に優しくない
MediaWikiには標準で全文検索機能がついていますが、検索結果はほぼ記事タイトルが出るだけで素っ気ない感じです。
<img width="800" alt="default-search.png" src="https://qiita-image-store.s3.amazonaws.com/0/150557/018226b5-4695-48a2-36d8-2df05e2f07a1.png">
<font color="Gray">※本記事の参考画像は、[青空文庫収録『草枕』](https://www.aozora.gr.jp/cards/000148/card776.html)を適当に区切ってページを作成した状態のWikiで作成しました。</font>

また、日本語の文章は単語ごとにスペース区切りがないため、標準の全文検索では**検索漏れ**が発生します。
例えば以下の画像では、「写生」のキーワードに対して表示される記事は1つだけなのに、「写生帖」にすると複数の記事が出てきます。単語が適切に分割されず、検索漏れが起きてしまったと考えられます。

<img width="800" alt="default-search2.png" src="https://qiita-image-store.s3.amazonaws.com/0/150557/93bc69b1-b16d-448d-a52f-27eb938e53cf.png">

せっかくWikiを整備したのに、必要な情報が検索に掛からないようでは困ってしまいます。そこで、CirrusSearchという検索用の拡張機能を導入します。

### CirrusSearch
[CirrusSearch](https://www.mediawiki.org/wiki/Help:CirrusSearch/ja)（シーラスサーチ）は、**MediaWikiの検索機能を強化**する拡張機能です。Wikipediaをはじめ、ウィキメディアプロジェクトは全てこの拡張を使用しています。
検索エンジンには**Elasticsearch**を使用しており、軽量に全文検索を行うことができます。

インストールの手順は公式の[Extension:CirrusSearch](https://www.mediawiki.org/wiki/Extension:CirrusSearch)に書かれている通りです。しかし、実際に辿ってみるとあちこち調べなければ手順の全貌が分からない上、何度か落とし穴にハマったので手順を残しておきます。

インストールの複雑さは開発側も承知のようで、拡張機能のページにも「分かりにくい依存関係をなんとかしたい」と書かれています。今後は楽にインストールできるようになるかもしれません。

## 環境
- CentOS `7.5`
    - 掲載する手順はCentOS7を前提としますが、他OSでも導入の流れは同じです
- [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki) `1.32.0`
- Elasticsearch `5.6.14`

**MediaWikiおよびCirrusSearchは活発に開発が行われているプロジェクトであり、以下の情報は最新のものでない可能性があります。**
**必ず公式のドキュメントやREADMEなどの一次情報と照らし合わせ、食い違いがあれば公式の指示に従ってください。**

## Elasticsearchを導入する
先述の通り、CirrusSearchはElasticsearchを使用するので先に導入しておく必要があります。

### Java（JDK）を入れる
Elasticsearchが動くためにJavaが必要なので入れましょう。

```shell-session
$ sudo yum -y install java-1.8.0-openjdk-devel
```

### Elasticsearch5 or 6を入れる
（古い情報）~~ここで早速落とし穴ですが、現時点で**CirrusSearchはElasticsearch5.xまでしか対応していません**。~~

MediaWikiのバージョンにより、インストールすべきElasticsearchのバージョンが違います。簡単に言うと、MediaWiki 1.32以前なら5.x、1.33以降なら6.xが必要です。
普通にインストールを進めると6.xが入るため、**MediaWikiのバージョンによっては**いざ起動する段階でこのように怒られて止まります。

```shell-session
`Only Elasticsearch 5.x is supported.  Your version: 6.5.4.`
````

基本的には[公式の手順](https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html)を守ればよいです。バージョンの`6.x`を`5.x`にするのを忘れないようにしましょう。

```shell-session
$rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
$ sudo vim /etc/yum.repos.d/elasticsearch.repo

name=Elasticsearch repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
$ sudo yum -y install elasticsearch
```

起動して動作確認します。

```shell-session
$ sudo systemctl enable elasticsearch
$ sudo systemctl start elasticsearch
$ curl http://127.0.0.1:9200
{
  "name" : "*******",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "**********************",
  "version" : {
    "number" : "5.6.14",
    "build_hash" : "f310fe9",
    "build_date" : "2018-12-05T21:20:16.416Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.1"
  },
  "tagline" : "You Know, for Search"
}
```

### analysis-kuromojiを入れる
`analysis-kuromoji`は、日本語の形態素解析を行ってくれるプラグインです。これがないと日本語の検索が不完全のままなので入れましょう。
Elasticsearchがきちんと入っていれば簡単にインストールできます。

```shell-session
$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji
$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin list
analysis-kuromoji
```

## Elasticaを導入する
MediaWikiとElasticsearchがやり取りするための拡張です。**[公式ページ](https://www.mediawiki.org/wiki/Extension:CirrusSearch/ja#Installation)**の「ダウンロード」リンクから、お使いのMediaWikiのバージョンに合ったものをダウンロードしてください。
以下は1.32の例です。

```shell-session
$ wget https://extdist.wmflabs.org/dist/extensions/Elastica-REL1_32-9fcf88c.tar.gz
$ tar -xzf Elastica-REL1_32-9fcf88c.tar.gz -C /MediaWikiが/ある/ディレクトリ/extensions
```

`LocalSettings.php`で読み込みます。

```php:LocalSettings.php
wfLoadExtension( 'Elastica' );
```

これだけではインストールしたことにならず、composerを使う必要があります。composerがない場合は**[公式](https://getcomposer.org/download/)**を参考に入れておいてください。

```shell-session
$ cd /MediaWikiが/ある/ディレクトリ/extensions/Elastica
$ composer install --no-dev
```

`index.php/特別:バージョン情報`をブラウザで開いてElasticaが増えていればOKです。
<img width="450" alt="version-elastica.png" src="https://qiita-image-store.s3.amazonaws.com/0/150557/5d3afb41-f2a3-a809-fee3-855049aa544c.png">


## CirrusSearchを導入する
### インストール
お疲れ様でした。やっと本体のインストールに入れます。

**[公式](https://www.mediawiki.org/wiki/Extension:CirrusSearch/ja#Installation)**からダウンロードしてextensionsディレクトリに展開するまではElasticaと同様です。
指示通りに`LocalSettings.php`へ追記し、バージョン情報で無事インストールできたか確認します。

```php:LocalSettings.php
require_once "$IP/extensions/CirrusSearch/CirrusSearch.php";
```

### インデックスの作成
ここからは[README](https://phabricator.wikimedia.org//r/p/mediawiki/extensions/CirrusSearch;browse/master/README)を見るようにと書いてあるので見に行きます。
以下作業内容を解説しますが、CirrusSearchのバージョンアップで変わる可能性があるためリンク先も合わせてご確認ください。インストールに関する部分は4-31行目あたりです。

指示通りに検索を一旦停止します。

```php:LocalSettings.php
wfLoadExtension( 'Elastica' );
wfLoadExtension( 'CirrusSearch' );
$wgDisableSearchUpdate = true;
```

インデックスの設定を作るスクリプトを実行します。

```shell-session
$ php extensions/CirrusSearch/maintenance/updateSearchIndexConfig.php
content index...
        Fetching Elasticsearch version...5.6.14...ok
        Scanning available plugins...none
...
                Updating tracking indexes...done
                Deleting namespaces...done
                Indexing namespaces...done
```

（コメントで情報いただきました）
`updateSearchIndexConfig.php`の実行に[失敗する場合があります](https://qiita.com/kn1cht/items/7906e3dc50cde20bf738#comment-aa072a927774663a51a5)。
修正が予定されていますが、発生した場合は`metastore.php`を実行することで回避できるようです。


最新版では上記の問題は修正されました。

再度検索を有効にします。

```diff:LocalSettings.php
- $wgDisableSearchUpdate = true;
```

いよいよインデックスを作成します。規模の大きいWikiの場合はそれなりに時間がかかるので、お茶でも飲んで待機します。

```shell-session
$ php extensions/CirrusSearch/maintenance/forceSearchIndex.php --skipLinks --indexOnSkip
[              wikidb] Indexed 10 pages ending at 10 at 13/second
Indexed a total of 10 pages at 13/second

$ php extensions/CirrusSearch/maintenance/forceSearchIndex.php --skipParse
[              wikidb] Indexed 10 pages ending at 10 at 10/second
Indexed a total of 10 pages at 10/second
```

ここまで来たら、検索エンジンをCirrusSearchに切り替えて作業完了です。

```diff:LocalSettings.php
+ $wgSearchType = 'CirrusSearch';
```

### 検索結果を確認する
検索してみてエラーが出なければ、導入完了です！　エラーが出た場合はメッセージでググる、これまでの作業で失敗していそうな部分をやり直すなどしてみましょう。

図は「写生」の検索結果です。これまで検索にかからなかった記事も発見できるようになりました。

<img width="800" alt="success.png" src="https://qiita-image-store.s3.amazonaws.com/0/150557/6b13873b-279d-62d2-6e2b-92ef9239d875.png">

## 付録：Elasticsearchのヒープサイズを抑制する
Elasticsearchはデフォルトでは2GBのヒープメモリを確保します。
安めのレンタルサーバやVPSでWikiを運用しており、メモリに余裕がないという場合は、消費できるヒープメモリを制限しておく必要があります。

こちらは所属団体のVPSでCirrusSearchを導入中、何も考えずにElasticsearchを起動した様子です。
大量のメモリスワップが発生してサーバが応答しなくなり、[Mackerel先生](https://mackerel.io)に怒られています。
<img width="700" alt="elastic-heavy.png" src="https://qiita-image-store.s3.amazonaws.com/0/150557/c48d04ce-3cd2-0658-2a77-fcb721375bdd.png">

これではよくないのでメモリを制限してから起動しましょう。以下の記事を参考に修正します。

- [Elasticsearch Logstash Kibanaの環境構築](https://thinkit.co.jp/article/13444)

`/etc/elasticsearch/jvm.options`を開いて`Xms`を探します（先頭にあるはずです）。`Xms`と`Xmx`には同じ値を設定します。
制限の値は環境によって試行錯誤が必要ですが、物理メモリの50%以下とするのがよいようです。

```diff:/etc/elasticsearch/jvm.options
  # Xms represents the initial size of total heap space
  # Xmx represents the maximum size of total heap space

- -Xms2g
+ -Xms500m
- -Xmx2g
+ -Xmx500m
```

Elasticsearchを再起動し、検索が軽くなっていればOKです。

```shell-session
$ sudo systemctl restart elasticsearch
```