セルフマネージド版のElastic App Searchを試してみた

# はじめに
Elastic Stack 7.2以降からElastic App Searchのセルフマネージド版が公開されたということで、試しにセルフマネージド版のElastic App Searchを使用してオンプレミス環境に検索エンジンを作成してみました。

その時に調べたElastic App Searchの概要と、お試しに作成した検索エンジンの構築の流れについて簡単に紹介します。

# Elastic App Searchとは
Elastic App Searchは、2017年にサイト内検索のSaaSを提供しているSwiftypeを買収してできたプロダクトで2018年5月からクラウドサービスとしてGAされていましたが、2019年6月にリリースされたElastic Stack 7.2.0からオンプレミス環境やIaaS環境で動くセルフマネージド版もGAされました。

Elastic App Searchは、高機能な検索エンジンの構築を簡素化するためのプロダクトで、Elasticsearchの機能を基に検索エンジンに必要な様々な機能がプリセットされており、開発者が素早く検索エンジンを構築するのを手助けしてくれます。

また、Elastic App Searchでは、直感的な管理ダッシュボードを提供しており、そのダッシュボードから簡単に検索エンジンのチューニングなどのカスタマイズを行うことができます。

Elastic App Searchの主な特徴としては以下の通りです。

- **幅広いデータに合わせてシンプルに実装**  
  データはスキーマレスで投入可能で、検索エンジンも英語や日本語、フランス語などの13ヵ国語それぞれに最適化されたエンジンを選択することができます。また、検索ワードのオートコンプリートや誤字の許容機能、ステミング、フィルタリングなど検索エンジンを実装するために必要な様々な機能も事前に設定済みで簡単に高機能な検索エンジンの構築を実現します。
    ![app_search_feature_001_tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/7ef26bff-c34c-ed49-4507-9499a1fc53dc.png)

- **直感的な検索エンジンのカスタマイズ**  
  Elastic App Searchの管理ダッシュボードを使用して直感的に検索の関連性のチューニングができます。同義語(シノニム)の設定や、特定のクエリにおける検索結果を並べ替えてある結果を上位に表示させるプロモーション機能、各フィールドの検索に対する重み付けや特定のワードにおけるブースト機能が使用でき、これらを使うことでより検索精度を高めることができます。
    ![app_search_feature_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/1c4e37d0-3929-4dca-4013-a0d439ef1ccd.png)

- **リアルタイムなアナリティクス**  
  検索クエリの実行回数やユーザがどのような検索クエリを実行したかなどをリアルタイムに可視化することができます。これによりユーザの行動を把握でき、検索体験をより良いものとするための手助けとなります。
   ![app_search_feature_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/ae3afa58-9fae-d534-0aa1-6461f6423b9b.png)

Elastic App Searchを利用して検索アプリケーションを開発するにあたって、開発者は、Elastic App Searchが提供する豊富な各種検索APIを使用することができます。また、Elastic社からPythonやRuby、JavaScriptなどの言語でSDKが提供されており、それらを使用することで効率的に検索アプリケーションを開発することができます。

さらに、Elastic社は、以下のGithubでReactベースのWeb UIを公開しており、Elastic App SearchのReference UIという機能を使うことで、すぐに検索用のWeb UIを使用することも可能です。

- elastic/app-search-reference-ui-react  
  [https://github.com/elastic/app-search-reference-ui-react](https://github.com/elastic/app-search-reference-ui-react)

#### セルフマネージド版のElastic App Searchについて
セルフマネージド版のElastic App Searchは、自前で用意したオンプレミス環境やIaaS環境のインスタンスに導入することができ、Elastic Stackと同様に無料で使い始めることができます。

セルフマネージド版のElastic App Searchを導入する場合、バックエンドのデータストアとしてElasticsearchを使用します。クライアントからのデータの投入や検索のリクエストはElastic App Searchに対して行われ、Elastic App SearchからElasticsearchに対してインデックス作成や検索などの操作が行われます。
![new_app_search_flow_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/5b10c286-8915-e172-10ba-599fc019a3b6.png)

# お試し検索エンジン構築の流れ
デモ環境やプロトタイプ環境を想定して最小限の設定や作業で、Elastic App Searchを使用した検索エンジンを構築する際の流れを記載しています。なお、検索エンジンを構築する上で使用した環境は以下の通りです。  

※ 今回使用した環境はデモなどを想定した簡易的な環境なので、ElasticsearchやElastic App Searchの推奨HWスペックには従っていません。

- 環境  
  - CentOS 7.7 x 1台 (vCPU x 2, Memory 16GB, Disk 50GB)
  - Elasticsearch 7.5.0
  - Elastic App Search 7.5.0
  - Docker 1.13.1
  - Docker Compose 1.24.1
  - Node.js 12.13.0
  - npm 6.12.0

また、検索エンジン構築の際の検索対象データとして、Strata Data Conference 2019 Londonの各セッション情報を事前にJSON形式に加工して用意していたので、そのデータを検索対象のサンプルデータとして使用します。

サンプルデータは以下のような形式で100ドキュメント分記載されたJSONファイル(sample-data.json)を自身のPCに保存しています。

```
[
	{
    "id": "sdc2019uk-c0d830f7d1177cbe98098b4a2672f45d",
    "title": "Hands-on data science with Python",
    "session_type": "Training",
    "topics": ["Data Science",	 "Machine Learning & AI"],
    "secondary_topics": [	"Data preparation",	 "data governance and data lineage"],
    "tech_component": ["Python", "scikit-learn"],
    "url": "https://conferences.oreilly.com/strata/strata-eu/public/schedule/detail/74482",
    "description": "Robert Schroll walks you through all the steps of developing a machine learning pipeline from prototyping to production. You'll explore data cleaning, feature engineering, model building and evaluation, and deployment and then extend these models into two applications from real-world datasets. All work will be done in Python.",
    "session_date": ["2019/04/29",	 "2019/4/30"]
	},
	{
    "id": "sdc2019uk-d3d9a315a1762afb59499e6b31165004",
    "title": "Expand your data science and machine learning skills with Python, R, SQL, Spark, and TensorFlow",
    "session_type": "Training",
    "topics": [	"Data Science",	 "Machine Learning & AI"],
    "secondary_topics": ["Deep Learning"],
    "tech_component": [	"Python",	"R", "SQL",	 "Spark", "TensorFlow"	],
    "url": "https://conferences.oreilly.com/strata/strata-eu/public/schedule/detail/74586",
    "description": "Advancing your career in data science requires learning new languages and frameworks?but learners face an overwhelming array of choices, each with different syntaxes, conventions, and terminology. Ian Cook simplifies the learning process by elucidating the abstractions common to these systems. Through hands-on exercises, you'll overcome obstacles to getting started using new tools.",
    "session_date": ["2019/04/29",	 "2019/4/30"]
	},
  ...
]
```

自身でサンプルデータを用意する際は、以下サイトのドキュメントを参考に用意してください。

- Schema Design, Field Type Overview  
    [https://swiftype.com/documentation/app-search/api/overview#schema-design](<https://swiftype.com/documentation/app-search/api/overview#schema-design>)
- Cerate or Update Documents  
    [https://swiftype.com/documentation/app-search/api/documents#create](<https://swiftype.com/documentation/app-search/api/documents#create>)


## 1. Elastic App Search導入
セルフマネージド版のElastic App Searchの導入方法として、RPMなどのパッケージで導入するパターンとDocker Composeを使用して導入するパターンの2パターンを紹介します。

### パターン1: RPMなどのパッケージを使用したElastic App Searchの導入
セルフマネージド版のElastic App Searchのパッケージは、Elastic社の以下のダウンロードサイトからダウンロードができます。ダウンロードできるパッケージの種類にはRPMやDebian、tar形式があります。

- Download Elastic App Search  
  [https://www.elastic.co/jp/downloads/app-search](<https://www.elastic.co/jp/downloads/app-search>) 

  ![app_search_000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/70b1eb7f-9400-8b79-aeea-db54dff7fd19.png)

RPMなどのパッケージを使用してElastic App Searchを導入する場合、事前にElasticsearchの環境とJava 8もしくはJava 11の環境を事前に用意しておく必要があります。ここでは、1台の環境にElasticsearchもJavaも導入済みの想定で記載しています。

Elastic App Searchのパッケージのダウンロード完了後、インストールを実施します。

```
$ sudo yum localinstall app-search-7.5.0.rpm
```

インストール完了後、Elastic App Searchに対して以下のように設定を加えます。

```
$ sudo vi /usr/share/app-search/config/app-search.yml
以下の設定を追記
app_search.external_url: http://<Elastic App Searchのホスト名もしくはIPアドレス>:3002
app_search.listen_host: 0.0.0.0
allow_es_settings_modification: true
```

なお、ElasticsearchのノードとElastic App Searchのノードが別の場合は、`elasticsearch.host=http://<Elasticsearchのホスト名もしくはIPアドレス>:9200`の設定も追記します。

設定完了後、以下のコマンドでElastic App Searchを起動することで、Elastic App Searchが利用可能になります。

```
$ sudo /usr/share/app-search/bin/app-search
```

### パターン2: Docker Composeを使用したElastic App Searchの導入
DockerおよびDocker Composeの環境がある場合、以下のyamlファイルを作成し、`docker-compose up`を実行することで、ElasticsearchとElastic App Searchの環境をまとめて用意することができます。

```
$ vi docker-compose.yml
version: '2.4'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.0
    environment:
      - "node.name=es-node"
      - "discovery.type=single-node"
      - "cluster.name=app-search-docker-cluster"
      - "bootstrap.memory_lock=true"
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test: ["CMD", "curl", "-f", "http://elasticsearch:9200"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

  appsearch:
    image: docker.elastic.co/app-search/app-search:7.5.0
    environment:
      - "elasticsearch.host=http://elasticsearch:9200"
      - "allow_es_settings_modification=true"
      - "JAVA_OPTS=-Xms2g -Xmx2g"
      - "app_search.listen_host=0.0.0.0"
      - "app_search.external_url=http://<Elastic App Searchのホスト名もしくはIPアドレス>:3002"
    ports:
      - 3002:3002
    depends_on:
      elasticsearch:
        condition: service_healthy
```

```
$ sudo docker-compose up
```

※ ElasticsearchとApp Searchのバージョンを7.5.0に指定し、Docker Composeを実行する場合、`heathcheck`と`depends_on`を設定しないとElasticsearchサービスが上がる前にApp SearchがElasticsearchに対して接続しにいくため、接続エラーが発生し、App Searchのコンテナが落ちるようです。
なお、ElasticsearchとApp Searchのバージョンを7.4.2に指定した場合は、上記の事象は発生しませんでした。

## 2. 検索エンジンの作成
Elastic App Searchの環境が用意できたらElastic App Searchの管理コンソールから検索エンジンを作成します。

Elastic App SearchのWeb UI(**http://\<Elastic App Searchのホスト名もしくはIPアドレス\>:3002**)にアクセスし、Welcome to Elastic App Searchの画面で**"Continue to Dashboard"**をクリックします。

![app_search_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/c07d4d98-fc7c-159e-8f49-bd0e79873a32.png)

検索エンジンの作成画面で、以下のようにEngine nameとLanguageを指定し、**"Continue"**をクリックします。

- Engine name: **sample-engine**
- Language: **English**

![app_search_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/90bcd0e3-87b1-287f-a771-3775b1559f6d.png)

検索エンジンの作成後、用意していたサンプルデータ(sample-data.json)を検索エンジンに追加するためにAdd documents to your Engine画面から**"Upload a JSON file"**をクリックします。

![app_search_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/28b3e354-8ecd-c332-5cd6-67b5bd51cd6a.png)

Document Importの画面から**"Choose File"**をクリックし、サンプルデータを追加した後、**"Continue"**をクリックします。

![app_search_004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/6ec7aa17-90e3-55d6-063c-25a0f9258b15.png)

検索エンジンにサンプルデータが正しく追加された場合、最終的に以下の画面が表示されるので、**"Visit the Dashboard"**をクリックします。

![app_search_005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/2cdd21d7-fd96-2fc6-a17c-e5c5913e9af5.png)

Engines画面から作成した検索エンジン(sample-engine)をクリックします。

![app_search_006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/f4f596ca-da57-0f2d-c0a1-8776873b8f19.png)

作成した検索エンジンのダッシュボードが表示され、このダッシュボードからの関連性のチューニングや管理などが行えます。

![app_search_007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/6880852b-d05a-5671-95b3-bf40208b7e96.png)

ここまでで、検索エンジンの機能については完成しました。検索エンジンに対してREST APIで検索クエリを実行することで、検索結果が返ってくるようになっています。

- 補足  
  検索エンジンへのデータの追加はREST APIによる追加も可能です。APIでデータを追加する場合は、検索エンジンのダッシュボードから**"Credentials"**をクリックし、private-keyをコピーし、メモしておきます。

    ![app_search_008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/b011e3e1-9fb7-3157-c0e1-54ce1337c82a.png)

    検索エンジンのprivate-keyをメモしたら、以下のようにJSONファイルをPOSTするリクエストを実行することで、検索エンジンへのデータの追加ができます。

    ```
    $ curl -XPOST "http://<Elastic App Searchのホスト名もしくはIPアドレス>:3002/api/as/v1/engines/<エンジン名>/documents" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer <メモしたprivate-key>" \
      -d "@sample-data.json"
    ```

## 3. 検索エンジンのUIの作成
Elastic App SearchのReference UI機能を使用し、作成した検索エンジンのWeb UIを作成します。

Elastic App Searchの作成した検索エンジンのダッシュボードから**"Reference UI"**をクリックします。そして、Create a New Refernece UI画面の各設定項目に対してここでは以下のように設定し、**"Generate a Preview"**をクリックします。

- Title field (各検索結果のタイトル行として表示)
    - 設定: **title**
- Filter fields (設定したフィールドの要素で検索結果をフィルタリング可能)
    - 設定: **topics**、**secondary_topics**
- Sort fields (指定したフィールドの要素で検索結果をソート可能)
    - 設定: **session_date**
- URL field (各検索結果のタイトル行にリンクを付与)
    - 設定: **url**

![app_search_009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/ceae9480-16a2-45d9-7087-03896cbbd3d3.png)

プレビューが作成されるとWeb UIのリファレンスが表示されます。そして、Reference UIの画面から検索できます。

![app_search_010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/67e25fb4-af19-9f40-2827-8943c7bdf40a.png)

このようにReference UIを使用することで、どのような検索体験となるか素早く把握することができます。また、このWeb UIは**"Download ZIP Package"**をクリックすることでダウンロードすることができます。

ダウンロードしたパッケージはElastic社が提供するWeb UIを基に、作成した検索エンジンに合わせてカスタマイズされています。

そして、ダウンロードしたパッケージを自身の環境(ここではCentOS 7.7の環境)で解凍し、以下のコマンドを実行することで、自身の環境で作成した検索エンジンにカスタマイズされたWeb UIを起動することができます。なお、Web UIを実行するにあたってはNode.jsとnpmを事前に用意しておく必要があります。

```
$ ls sample-engine
sample-engine-react-demo-ui.zip
$ cd sample-engine
$ unzip sample-engine-react-demo-ui.zip
$ ls
bin                  package.json       sample-engine-react-demo-ui.zip
LICENSE.txt          package-lock.json  scripts
logo-app-search.png  public             src
NOTICE.txt           README.md
```

```
$ npm install
$ npm start
Compiled successfully!

You can now view app-search-reference-ui-react in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://<検索用Web UI起動環境のホスト名もしくはIPアドレス>:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.
```

Web UIを起動後、Webブラウザから**http://\<検索用Web UI起動環境のホスト名もしくはIPアドレス\>:3000**にアクセスすることで、検索画面が表示されます。そして、以下のように検索ボックスに検索ワードをいれ、検索することができます。

![app_search_011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538823/8e85a973-c05b-2052-c173-93c47a5951c0.png)

なお、`src/config/engine.json`の設定やHTMLファイルやJavaScriptファイルなどを変更することで、Web UIのレイアウトの変更も可能です。詳細については、[elastic/app-search-reference-ui-react](https://github.com/elastic/app-search-reference-ui-react)にあるREADME.mdなどを確認してください。

# さいごに
Elastic App Searchの概要とElastic App Searchを使ってお試しの検索エンジンを作る方法を紹介してきました。

検索エンジンを作る方法については、もしプロダクション環境でも使用するようなWeb UIを作るようであれば、Reference UIを使用せず、Elastic App Searchが提供するAPIや様々な言語のSDKを駆使して作るとか思います。

ただ、Reference UIを使ったWeb UIもデモやプロトタイプとして使用するのには有用なものだと思いますし、簡単に作成できますので、是非試してみてください。

# 参考
- Elastic App Search  
  [https://www.elastic.co/jp/products/app-search](https://www.elastic.co/jp/products/app-search)
- App Search Documentation  
  [https://swiftype.com/documentation/app-search/getting-started](https://swiftype.com/documentation/app-search/getting-started)
- Swiftype App Search Public Beta Now Available for Developers  
  [https://www.elastic.co/blog/swiftype-app-search-public-beta-available](https://www.elastic.co/blog/swiftype-app-search-public-beta-available)
- Elastic App Search: Now Available as a Self-managed Download  
  [https://www.elastic.co/blog/elastic-app-search-7-2-0-released](https://www.elastic.co/blog/elastic-app-search-7-2-0-released)