RedashのQueryRunnerを拡張する


RedashのElasticsearch用のパーサー（QueryRunner）に問題（[RedashでデータソースにElasticsearchを使用した時の問題](https://qiita.com/J-SHK/items/e834e4f14f6bdf105624)）を発見したので、問題を解決するためにQueryRunnerを拡張します。
既存ファイルを修正して、対応する事も可能でしたが、それだとバージョンアップの際に手間となるので、今回はQueryRunnerを新規に追加してみました。

# 環境
Redash(v7.0.0)
Elasticsearch(v7.3.2)
docker

# 拡張内容
Elasticsearchで複数Aggregationのクエリ結果をRedashの結果として、表形式で正しく表示する。
具体的には、GROUP BY 項目1,項目2のように指定した時と同じような表結果を得られれば、Redashでグラフを作成する事が可能なため。

以下のようなElasticsearchからのクエリ結果を表形式にパースする。（結果構造から一部データを省略）

```
{
	"aggregations": {
		"1st": {
			"buckets": [
				{
					"key": "2019年10月29日",
					"doc_count": 60,
					"2nd": {
						"buckets": [
							{
								"key": "システム部",
								"doc_count": 10
							},
							{
								"key": "人事部",
								"doc_count": 20
							},
							{
								"key": "総務部",
								"doc_count": 30
							}
						]
					}
				},
				{
					"key": "2019年10月30日",
					"doc_count": 600,
					"2nd": {
						"buckets": [
							{
								"key": "システム部",
								"doc_count": 100
							},
							{
								"key": "人事部",
								"doc_count": 200
							},
							{
								"key": "総務部",
								"doc_count": 300
							}
						]
					}
				}
			]
		}
	}
}
```

# Redashへの追加方法

新規のQueryRunnerを追加する場合には、予め用意されている環境変数"REDASH_ADDITIONAL_QUERY_RUNNERS"で追加が行えます。

[Redashで用意されている環境変数の一覧](https://redash.io/help/open-source/admin-guide/env-vars-settings)

### 追加の読み込み設定
docker-compose.ymlに設定の追加を行います。
追加はenvironmentのセクションに追記します。

```docker-compose.yml
environment:
  REDASH_ADDITIONAL_QUERY_RUNNERS: "redash.query_runner.elasticsearch_custamize"
```

### 追加ファイルの配置
既に既存のファイルが配置されているディレクトリ内に、今回追加するファイルを配置します。

```
redash/query_runner
　elasticsearch.py
　oracle.py
　pg.py
   ・
   ・
　elasticsearch_custamize.py
   ・
```

### Dockerコンテナの起動（再起動）
開発版で確認する場合、redash直下のdocker-compose.ymlをベースに、docker-composeを行います。
リリース版で確認する場合、予めファイルを配置したRedashのImageを作成しておくなりして、redash/setup直下のdocker-compose.ymlをベースに、docker-composeを行います。
※起動時に追加指定した箇所に対象のファイルがないとエラーになります。

```
redash
  /setup
    docker-compose.yml ← リリース版用
  Dockerfile
  docker-compose.yml 　← 開発用
```

# 追加したQueryRunnerの使用
### New Data Sourceから追加したData Sourceを選択する。
正しく読み込めていると、Data Sourceの一覧に表示されます。
※Data Sourceに対する画像が別で管理されているようで、今回は既存のElasticsearchを残したまま別名で作成したので、何も画像が表示されていないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521484/e3b555b4-17f5-3707-03e1-023af79cb828.png)

下記のように名前をずらさないと、既存の物が上書きされるので、注意が必要。

```elasticsearch_custamize.py
class ElasticsearchCustom(BaseElasticSearch):

    @classmethod
    def name(cls):
        return 'ElasticsearchCustom'

register(ElasticsearchCustom)
```

Elasticsearchの接続情報を入力してSAVEを行う。
今回追加したelasticsearch_custamize.pyで設定情報を定義する事となりますが、今回は既存のelasticsearch.pyの拡張版の為、接続定義情報は既存のElasticsearchと同じように登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521484/35ed97aa-dacc-41c7-d373-91510811b61c.png)

### Queryから登録したData Sourceを使用してクエリを作成して、実行
実行するクエリは下記の通り。

```
{
    "index": "インデックス名",
    "size": 100,
    "aggs": {
        "1st": {
            "terms": {
                "field": "LogDate"
            },
            "aggs": {
                "2nd": {
                    "terms": {
                        "field": "SectionName"
                    }
                }
            }
        }
    }
}
```

elasticsearch_custamize.pyで処理した結果が、Tableに表示される。

| 1st| 2nd | 1st_doc_count | 2nd_doc_count |
|:-----------------|:-----------------|-----------------:|-----------------:|
| 2019年10月29日 | システム部 | 60 | 10 |
| 2019年10月29日 | 人事部 | 60 | 20 |
| 2019年10月29日 | 総務部 | 60 | 30 |
| 2019年10月30日 | システム部| 600 | 100 |
| 2019年10月30日 | 人事部 | 600 | 200 |
| 2019年10月30日 | 総務部 | 600 | 300 |

この表結果が得られれば、グラフを作成できる！

もしこれでカバーできない要件が来た時に、色々なクエリ結果のJSONパターンを加味して、プログラムを複雑化させるよりかは、QueryResultの合わせ技で実現するのも手かなと。