Elasticsearchを推薦システムとして使う（関連アイテム推薦）

こんにちは[rilmayer](https://twitter.com/rilmayer_jp)です。
この記事はアドベントカレンダー「[Search&Discovery 全部俺](https://adventar.org/calendars/4691)」18日目の記事となります。（遅れ

本日は定番のOSS全文検索エンジンである[Elasticsearch](https://www.elastic.co/jp/what-is/elasticsearch)を推薦システムとして使ってみようと思います。

基本的な操作は以前[こちらの記事](https://qiita.com/rilmayer/items/5e24d0c6484196f0cc07)でご紹介しましたが、おさらいをかねてやっていこうと思います。

## Elasticsearchの立ち上げ
やはりDockerが楽なのでDockerイメージで立ち上げてみます。

```Dockerfile:Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:7.5.0
RUN bin/elasticsearch-plugin install analysis-kuromoji
```

以下のようにbuildしてrunすれば立ち上がります。

```bash
# build
docker build -t es .

# run
# 中に入る場合
docker run -i  -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" es bash

# デーモンとして起動する場合
docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node"  es
```

## アイテムの投入
今までと同じくアイドルデータを追加してみます。

```python
from elasticsearch import Elasticsearch

# インデックス作成
host = 'http://localhost:9200/'
es = Elasticsearch(host)
index_name = 'my_favorite_idols'
es.indices.create(index=index_name, body={
    'settings': {
            'number_of_shards': 5,
            'number_of_replicas': 0
    },
    'mappings': {
        'properties': {
            'idol_name': {
                'type': 'text',
                'analyzer': 'kuromoji'
            },
            'description': {
                'type': 'text',
                'analyzer': 'kuromoji'
            }
        }
    }
})

```

### アイドルデータの追加
チクチクアイドルデータを追加していたのですが、めんどくさくなったので[こちら](http://ja.dbpedia.org/)のサイトでSPARQという問い合わせ言語を使ってwikiのデータをバコッと取得しました。

```SPARQL
select distinct ?name ?abstract where {
    ?idol <http://dbpedia.org/ontology/wikiPageWikiLink> <http://ja.dbpedia.org/resource/Category:日本のアイドルグループ> .
    ?idol rdfs:label ?name .
    ?idol <http://dbpedia.org/ontology/abstract> ?abstract .
}
LIMIT 1000
```

上記で取得したデータをCSVとして取得して以下のようにアイテムを追加します。
おそらく650くらいのアイドル情報が入手できるはずです。

```
# ファイル読み込み
import pandas as pd
csv_file_path = "idol.csv"
df = pd.read_csv(csv_file_path)

# アイテム投入
for i, row in df.iterrows():
    item = {'idol_name': row["name"], 'description': row.abstract}
    es.index(index=index_name, body=item)
```

これでアイテムが投入されました。

## 特定アイテムに似ているアイテムを取得する
Elasticsearchには[more_like_this](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html)という便利な機能が提供されています。

アイテムのIDを取得して以下のアイテムをベースに類似検索（関連アイテム推薦）を行ってみます。

```python

query = '東京女子流'
es_query = {
    "query": {
        "multi_match": {
            "query":    query
        }
    }
}
results = es.search(index=index_name, body=es_query)
print('hit:  ', results['hits']['total']['value'])
for i, result in enumerate(results['hits']['hits']):
    print(f"[{result['_id']}]", result['_source']['idol_name'], ':  ', result['_source']['description'][0:50])
```

上記で取得したIDを元に類似検索をします。

```python
def get_similar_items(item_id):
    es_query = {
        "query": {
            "more_like_this" : {
                "fields" : ["title", "description"],
                "like" : [
                    {
                        "_id" : item_id
                    }
                ],
                "min_term_freq" : 1,
                "max_query_terms" : 12,
                "minimum_should_match": 1
            }
        }
    }
    results = es.search(index=index_name, body=es_query)
    return results

item_id = [取得したID]
results = get_similar_items()
for i, result in enumerate(results['hits']['hits']):
    print(f"[{result['_id']}]", result['_source']['idol_name'], ':  ', result['_source']['description'][0:50])
```

以下のような結果が得られました。

```
[0] SweetS :   SweetS（スイーツ）は、日本の女性5人組ダンス＆ボーカルユニット。エイベックス・エンタテインメン
[1] Cheeky Parade :   Cheeky Parade（チィキィパレード）は、2012年に結成された日本の9人組女性アイドルグル
[2] GEM (アイドルグループ) :   GEM（ジェム）は、2012年に結成された日本の女性アイドルグループ、ダンス&ボーカルグループ。所属
[3] SUPER☆GiRLS :   SUPER☆GiRLS（スーパーガールズ）は、エイベックスのオーディションにより、2010年に結成さ
[4] フェアリーズ :   フェアリーズ（Fairies）は、日本の6人組女性アイドルグループ、ダンスボーカルグループで、201
[5] SPEED :   SPEED（スピード）は、日本の女性4人組のボーカル&ダンスグループ。メンバー全員が沖縄県出身。プロ
[6] W-inds. :   w-inds. （ウィンズ）は、日本の男性ダンス&ボーカルユニット。所属事務所はライジングプロダクシ
[7] DA PUMP :   DA PUMP（ダパンプ）は、日本のヒップホップダンスボーカルユニット。所属事務所はライジングプロダ
[8] Dancing Dolls :   Dancing Dolls（ダンシングドールズ）は、日本の5人組女性ダンス・ボーカルユニット。
[9] チェリーブロッサム :   チェリーブロッサムは、日本の6人組女性アイドル・ダンス&ボーカルグループである。愛称は、チェリブロ。
```

ぽいような気もするけれど、あくまで出てくる単語ベースなのでもう少し頑張りたいという感じもあります。
パラメータもいくつかあるのでチューニングしながら使ってみると良いかもしれません。

# おわりに
アイテムをインプットとして関連するアイテムを推薦するのも推薦システムの一つの方法です。
この方法はユーザー行動がなくてもできるので、立ち上げたばかりのサービスな度で非常に有効です。

ユーザーの情報を使ってランキングなどを行うのはまた別の工夫が必要となります。