【翻訳】検索結果の集計ライブラリevalcatの紹介

# はじめに（これは翻訳内容ではありません）
私がお手伝いしている[株式会社Libora](https://libora.jp/)では、インターン生に検索システムの改善に取り組んでもらっていました。
その取り組みの中で検索システムを評価するために作ってもらったいくつかのコードが有用そうだったので「OSSにしちゃいましょう！」と言うことで公開してもらい、簡単な使い方等の記事を書いてもらいました。

> Introducing evalcat - Masaki - Medium
> https://medium.com/@masaki.1996/introducing-evalcat-d57a04247305

新しく検索エンジンに変更を加えた時、ユーザーの反応を見る前に（適合評価やA/Bテストの前に）、「検索結果がどのくらい変わるのか？」と言うことを知りたいことはよくあると思います。
そのあたりを程よくカスタマイズして集計できるライブラリとなっていると思います。

実はElasticsearchの方に[eland](https://github.com/elastic/eland)という類似した非常に洗練されたライブラリがあるのですが、今回公開してもらった[evalcat](https://github.com/libora-com/evalcat)の方は主に「2つ以上の検索システム間評価」がより簡単にできることを目的にしています。


# 翻訳内容ここから
### はじめに
私はこの1年間、東京を拠点とするスタートアップ企業[Libora](https://libora.jp/)でインターンをしていて、オンライン講座の検索エンジンである[社名と同名のサービス](https://libora.com/ja/)に携わっていました。そこでは検索エンジンが完成した後、次のステップとして私は検索効果の改善に携わりました。
改善のため、検索アルゴリズムに変更を加えていくうちに、以前の検索結果と新しい検索結果を比較・評価するためのコードを常に再利用していることに気づきました。そこで、関数を抽出してライブラリevalcatにパッケージ化することにしました。

### 検索システムの評価
ElasticsearchやSolrのようなオープンソースの検索エンジンによって、検索システムの構築はよりシンプルなものになっています。一方で、検索システムを改善するときその有効性を検証しますが、その作業は多くの場合手間のかかるものとなっています。検索システムの評価は、通常、適合性評価、ログ分析、A/Bテストなど、オフライン評価とオンライン評価など複数の工程で構成されています。

検索評価には、前述の工程に先行するものがあり、その一つはクエリの検索結果を調べることです。これは、2つの検索システム（一般的には現行システムと改良したシステム）の統計指標を比較することで達成できます。この作業は適合性の評価とは異なるものですが、システム変更による影響を確認するために有用です。

### Evalcat
https://github.com/libora-com/evalcat

Evalcatは複数システムや複数クエリの検索結果を集計し比較できるライブラリです。
このライブラリでは、検索結果はフィールド（データベースのカラムなどに相当）の値ごとに集約されます。
例えば、検索結果に価格のフィールドが含まれている場合、結果の平均値とパーセンタイル値を計算することができます。

さらいに、システムやクエリ間でこれらの集計をすることができ、集約された統計指標は[pandasのDataFrame](https://pandas.pydata.org/pandas-docs/stable/getting_started/dsintro.html#dataframe)で返されます。
また、[RBO(ranked-biased overlap)](https://dl.acm.org/doi/10.1145/1852102.1852106)を計算する関数などが用意されており、それらを使用して、クエリや検索システム間の比較することができます。
Evalcatはさまざまな検索アルゴリズムを実験したときの検索結果の変化を理解することを目的に作られています。当初はElasticsearchの集計を集計して可視化することから始めましたが、後にユーザーの定義する様々な統計指標を計算できるように拡張しました。


### Evalcatの使い方
では実際に利用例をみていきまましょう。
以下の例では2つのシステム検索結果が与えられています。
それぞれ「オレンジ」と言うクエリの検索結果について、「id」と「価格」の2つのフィールドを含むアイテムのランキングになっています。

```python
search_results = {
    "system A": {
        "orange": [{"id":1, "price":1.3}, {"id":2, "price":2.5}],
    },
    "system B": {
        "orange": [{"id":1, "price":1.3}, {"id":3, "price":0.9}],
    },
}
```

価格フィールドの統計値を取得するために、価格が連続変数であることを示す `NumericalField` オブジェクトをインスタンス化します。このクラスは、そのフィールドのパーセンタイルと平均値を計算するメソッドを提供します。

```python
>>> price_field = NumericalField("price")
```

evalcatのメインクラスは `ResultList` です。検索結果とフィールドを引数として渡すことで、`get_system_metric_df()` メソッドを使って "orange" と言うクエリについての統計指標を見ることができます。

```python
>>> result_list = ResultList(search_results, [price_field])
>>> result_list.get_system_metric_df('price', 'orange')
```
```
+----------+---------------+---------------+-------+-------+
|          | 25-percentile | 50-percentile | total |  mean |
+----------+---------------+---------------+-------+-------+
| system A |      1.6      |      1.6      |  3.8  |  1.9  |
| system B |      1.0      |      1.1      |  2.2  |  1.1  |
+----------+---------------+---------------+-------+-------+
```

上記は単純な例ですが、定義した指標について検索システムを簡単に比較できるとことがこのライブラリの重要な特徴となります。
Fieldクラスは、ユーザー定義の指標計算関数へと拡張されることを意図しています。

### 今後について
Evalcatはまだできたばかりで、現在は実際の利用に際して足りない部分がありますが、今後も継続的に新しい機能を追加していく予定です。現時点では、次のステップとしてElasticsearchとの接続がスムーズにできる機能を予定しています。
もし気になる方がいらっしゃいましたらバグ報告やプルリクエストお待ちしております。