Tradeoff AnalyticsでAMIMOTOマネージドの最適プランを調べてみる
Tradeoff Analyticsについて Tradeoff Analyticsについては下の記事で紹介書いてるので、参考にしてください。 https://wp-kyoto.cdn.rabify.me/try-to-r […]
目次
Tradeoff Analyticsについて
Tradeoff Analyticsについては下の記事で紹介書いてるので、参考にしてください。
https://wp-kyoto.cdn.rabify.me/try-to-run-tradeoff-analytics/
どうせなら身近なものでテストしてみたいなと思ったので、ウチのサービスを題材にしてみました。
やってみたいこと
「価格・PV・WordPressインストール数とDBタイプの4種類から、希望条件に近いプランのリスト」を出すということを試してみます。
リクエストJSONを作る
最終的には1つのJSONにまとめますが、とりあえずパーツごとに作ります。
プロダクトリストを作る
まずは候補リストから。
候補はoptionsの中にリストとしてまとめていきます。
データソース
データはプラン一覧から拾ってきます。
https://ja.amimoto-ami.com/plans/hosting/single-instance-plan/
https://ja.amimoto-ami.com/plans/hosting/multi-instances-plan/
JSON
valuesの中に、価格・PV・DBタイプ・WordPressインストール数を入れてます。
"options": [
{
"key": "1",
"name": "t2.micro",
"values": {
"price": 3000,
"pv": 100000,
"db": "EC2",
"wp": 3
}
},{
"key": "2",
"name": "t2.small",
"values": {
"price": 6000,
"pv": 300000,
"db": "EC2",
"wp": 3
}
},{
"key": "3",
"name": "t2.medium",
"values": {
"price": 15000,
"pv": 500000,
"db": "EC2",
"wp": 3
}
},{
"key": "4",
"name": "c4.large",
"values": {
"price": 20000,
"pv": 1000000,
"db": "EC2",
"wp": 5
}
},{
"key": "5",
"name": "c4.8large",
"values": {
"price": 350000,
"pv": 20000000,
"db": "EC2",
"wp": 5
}
},{
"key": "6",
"name": "w-Small",
"values": {
"price": 80000,
"pv": 3000000,
"db": "RDS-Single",
"wp": 5
}
},{
"key": "7",
"name": "w-Large",
"values": {
"price": 120000,
"pv": 6000000,
"db": "RDS-Single",
"wp": 5
}
},{
"key": "8",
"name": "w-XLarge",
"values": {
"price": 160000,
"pv": 10000000,
"db": "RDS-Single",
"wp": 10
}
},{
"key": "9",
"name": "w-2XLarge",
"values": {
"price": 320000,
"pv": 20000000,
"db": "RDS-Single",
"wp": 10
}
},{
"key": "10",
"name": "HA-Small",
"values": {
"price": 120000,
"pv": 3000000,
"db": "RDS-Multi",
"wp": 5
}
},{
"key": "11",
"name": "HA-Large",
"values": {
"price": 180000,
"pv": 6000000,
"db": "RDS-Multi",
"wp": 5
}
},{
"key": "12",
"name": "HA-XLarge",
"values": {
"price": 200000,
"pv": 10000000,
"db": "RDS-Multi",
"wp": 10
}
},{
"key": "13",
"name": "HA-2XLarge",
"values": {
"price": 460000,
"pv": 20000000,
"db": "RDS-Multi",
"wp": 10
}
}
]
検索条件を入れる
columnsキーの中に検索候補を入れていきます。
"columns": [
{
"key": "price",
"type": "numeric",
"goal": "min",
"is_objective": true,
"full_name": "Price",
"range": {
"low": 0,
"high": 300000
},
"format": "currency: 'JPY¥' : 2"
},{
"key": "pv",
"type": "numeric",
"goal": "max",
"is_objective": true,
"full_name": "Monthly Pageview",
"range": {
"low": 10000000,
"high": 20000000
},
"format": "number:2"
},{
"key": "db",
"type": "categorical",
"goal": "min",
"is_objective": true,
"full_name": "Database Type",
"range": [
"EC2",
"RDS-Single",
"RDS-Multi"
],
"preference": [
"EC2",
"RDS-Single",
"RDS-Multi"
]
},{
"key": "wp",
"type": "numeric",
"goal": "max",
"is_objective": true,
"full_name": "WordPress installation ",
"range": {
"low": 1,
"high": 10
}
}
]
検索条件を表にまとめるとこうなります。
| 項目名 | 範囲 |
|---|---|
| 価格 | 0~300,000円 |
| PV | 10,000,000~20,000,000 PV |
| DBタイプ | EC2内DB > RDS1台 > RDSマルチAZ |
| WPインストール数 | 1 ~ 10 |
categoricalの分類方法
preferenceの配列順序でレコメンド度合いを取ります。
goalをmaxにした場合は配列の後ろの方にあるものを優先、minにした場合は前にあるものを優先します。
JSONにまとめる
最後にsubjectにタイトルを付けて、JSONにまとめます。
まとめたものが以下の通り。
{
"subject": "amimoto",
"columns": [
{
"key": "price",
"type": "numeric",
"goal": "min",
"is_objective": true,
"full_name": "Price",
"range": {
"low": 0,
"high": 300000
},
"format": "currency: 'JPY¥' : 2"
},{
"key": "pv",
"type": "numeric",
"goal": "max",
"is_objective": true,
"full_name": "Monthly Pageview",
"range": {
"low": 10000000,
"high": 20000000
},
"format": "number:2"
},{
"key": "db",
"type": "categorical",
"goal": "min",
"is_objective": true,
"full_name": "Database Type",
"range": [
"EC2",
"RDS-Single",
"RDS-Multi"
],
"preference": [
"EC2",
"RDS-Single",
"RDS-Multi"
]
},{
"key": "wp",
"type": "numeric",
"goal": "max",
"is_objective": true,
"full_name": "WordPress installation ",
"range": {
"low": 1,
"high": 10
}
}
],
"options": [
{
"key": "1",
"name": "t2.micro",
"values": {
"price": 3000,
"pv": 100000,
"db": "EC2",
"wp": 3
}
},{
"key": "2",
"name": "t2.small",
"values": {
"price": 6000,
"pv": 300000,
"db": "EC2",
"wp": 3
}
},{
"key": "3",
"name": "t2.medium",
"values": {
"price": 15000,
"pv": 500000,
"db": "EC2",
"wp": 3
}
},{
"key": "4",
"name": "c4.large",
"values": {
"price": 20000,
"pv": 1000000,
"db": "EC2",
"wp": 5
}
},{
"key": "5",
"name": "c4.8large",
"values": {
"price": 350000,
"pv": 20000000,
"db": "EC2",
"wp": 5
}
},{
"key": "6",
"name": "w-Small",
"values": {
"price": 80000,
"pv": 3000000,
"db": "RDS-Single",
"wp": 5
}
},{
"key": "7",
"name": "w-Large",
"values": {
"price": 120000,
"pv": 6000000,
"db": "RDS-Single",
"wp": 5
}
},{
"key": "8",
"name": "w-XLarge",
"values": {
"price": 160000,
"pv": 10000000,
"db": "RDS-Single",
"wp": 10
}
},{
"key": "9",
"name": "w-2XLarge",
"values": {
"price": 320000,
"pv": 20000000,
"db": "RDS-Single",
"wp": 10
}
},{
"key": "10",
"name": "HA-Small",
"values": {
"price": 120000,
"pv": 3000000,
"db": "RDS-Multi",
"wp": 5
}
},{
"key": "11",
"name": "HA-Large",
"values": {
"price": 180000,
"pv": 6000000,
"db": "RDS-Multi",
"wp": 5
}
},{
"key": "12",
"name": "HA-XLarge",
"values": {
"price": 200000,
"pv": 10000000,
"db": "RDS-Multi",
"wp": 10
}
},{
"key": "13",
"name": "HA-2XLarge",
"values": {
"price": 460000,
"pv": 20000000,
"db": "RDS-Multi",
"wp": 10
}
}
]
}
あとはこれをPOSTでwatson APIにぶん投げます。
Tradeoff Analytics APIで分析する
検索パラメータができたので、あとはAPIを使って解析します。
$ curl -X POST --user YOUR_USERNAME:YOUR_PASSWORD \ --header "Content-Type: application/json" \ --data @problem.json \ "https://gateway.watsonplatform.net/tradeoff-analytics/api/v1/dilemmas?generate_visualization=false"
戻り値を確認する
リクエストパラメータなども含まれた状態で返ってくるので、jqで見たい部分だけ抜き出します。
$ curl -X POST --user YOUR_USERNAME:YOUR_PASSWORD \
--header "Content-Type: application/json" \
--data @problem.json \
"https://gateway.watsonplatform.net/tradeoff-analytics/api/v1/dilemmas?generate_visualization=false" \
| jq ".resolution"
{
"solutions": [
{
"solution_ref": "1",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"1\" has a value in column \"pv\" which is:\"100000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"100000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "2",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"2\" has a value in column \"pv\" which is:\"300000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"300000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "3",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"3\" has a value in column \"pv\" which is:\"500000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"500000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "4",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"4\" has a value in column \"pv\" which is:\"1000000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"1000000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "5",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"5\" has a value in column \"price\" which is:\"350000\" while the column range\" is: [0.0,300000.0]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"price",
"350000",
"[0.0,300000.0]"
]
}
},
{
"solution_ref": "6",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"6\" has a value in column \"pv\" which is:\"3000000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"3000000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "7",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"7\" has a value in column \"pv\" which is:\"6000000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"6000000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "8",
"status": "FRONT"
},
{
"solution_ref": "9",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"9\" has a value in column \"price\" which is:\"320000\" while the column range\" is: [0.0,300000.0]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"price",
"320000",
"[0.0,300000.0]"
]
}
},
{
"solution_ref": "10",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"10\" has a value in column \"pv\" which is:\"3000000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"3000000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "11",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"11\" has a value in column \"pv\" which is:\"6000000\" while the column range\" is: [1.0E7,2.0E7]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"pv",
"6000000",
"[1.0E7,2.0E7]"
]
}
},
{
"solution_ref": "12",
"status": "EXCLUDED"
},
{
"solution_ref": "13",
"status": "INCOMPLETE",
"status_cause": {
"message": "A column of a option is out of range. Option \"13\" has a value in column \"price\" which is:\"460000\" while the column range\" is: [0.0,300000.0]",
"error_code": "RANGE_MISMATCH",
"tokens": [
"price",
"460000",
"[0.0,300000.0]"
]
}
}
]
}
solutions.statusを確認していくと、solutions.solution_refが8のオブジェクトのみFRONTで、それ以外はINCOMPLETEやEXCLUDEDになっています。
INCOMPLETEはrangeの範囲外の値が設定されているもの、EXCLUDEDはTradeoff Analyticsが最適解で無いと判断したもので、FRONTとなっているものがTradeoff Analyticsからレコメンドされるアイテムです。
ということで今回はsolutions.solution_refが8のプランが希望する条件に一致する様子です。
solutions.solution_refはoptions.keyの値と同じなので、options.keyが8のアイテムを見てみましょう。
{
"key": "8",
"name": "w-XLarge",
"values": {
"price": 160000,
"pv": 10000000,
"db": "RDS-Single",
"wp": 10
}
}
と、いうことで
| 項目名 | 範囲 |
|---|---|
| 価格 | 0~300,000円 |
| PV | 10,000,000~20,000,000 PV |
| DBタイプ | EC2内DB > RDS1台 > RDSマルチAZ |
| WPインストール数 | 1 ~ 10 |
の条件に一致するプランは「w-XLarge」だということになりました。
"solution_ref": "12"がEXCLUDEDになっていますが、これはDBタイプが「RDS-Multi」と一番低い優先順位になっているためだと思われます。
{
"key": "12",
"name": "HA-XLarge",
"values": {
"price": 200000,
"pv": 10000000,
"db": "RDS-Multi",
"wp": 10
}
}
optionsのkey: dbのgoalをminではなくmaxに変更すると、このHA-XLargeプランもFRONTとなります。
まとめ
「複数の条件から最適なプランを探す」というのはシステム化するのが手間な印象がありましたが、Tradeoff Analyticsを使うことでJSONさえ作ればかなり簡単に作れることがわかりました。
あとはJSON生成の自動化やプランレコメンド調査用のUIを作るところのノウハウなどが集まるようになれば、もっと便利になるかなと思います。