📝
ブラウザゲームの分析結果を Data Firehose に送信して Athena で分析してみた
ブラウザのじゃんけんゲームのログを送信、分析してみました。

01. IAM ユーザーの作成
- AdministratorAccess アクセス権限を付与した IAM ユーザーを作成
- アクセスキーを発行
02. S3 バケットの作成
- デフォルト設定で作成
03. Data Firehose ストリームの作成
- ソース: Direct PUT
- 送信先: Amazon S3
- Firehose ストリーム名: 任意
- 送信先の S3 バケット: 02 で作成した S3 バケット
- S3 バケットプレフィックス:
year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}/ - S3 バケットエラー出力プレフィックス:
error/!{firehose:error-output-type}/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/ - バッファサイズ: 1 MiB
- バッファ間隔: 60 秒
04. じゃんけんゲーム作成
以下のコードで index.html を作成します。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>じゃんけんゲーム</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
.choice { font-size: 50px; margin: 20px; cursor: pointer; padding: 20px; border: 2px solid #ccc; display: inline-block; }
.choice:hover { background-color: #f0f0f0; }
.result { font-size: 24px; margin: 30px; }
.score { font-size: 18px; margin: 20px; }
.config { background: #f5f5f5; padding: 20px; margin: 20px; border-radius: 5px; }
.config input { margin: 5px; padding: 5px; width: 300px; }
.config button { padding: 10px 20px; margin: 10px; }
</style>
</head>
<body>
<h1>じゃんけんゲーム</h1>
<!-- AWS設定セクション -->
<div class="config">
<h3>AWS設定</h3>
<input type="text" id="accessKey" placeholder="AWS Access Key ID">
<input type="password" id="secretKey" placeholder="AWS Secret Access Key">
<button onclick="configureAWS()">AWS設定を保存</button>
<p id="awsStatus">AWS未設定</p>
</div>
<div class="score">
<p>勝ち: <span id="wins">0</span> | 負け: <span id="losses">0</span> | あいこ: <span id="draws">0</span></p>
</div>
<div>
<div class="choice" onclick="playGame('rock')">✊<br>グー</div>
<div class="choice" onclick="playGame('paper')">✋<br>パー</div>
<div class="choice" onclick="playGame('scissors')">✌️<br>チョキ</div>
</div>
<div class="result" id="result"></div>
<!-- AWS SDK -->
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1563.0.min.js"></script>
<script>
let wins = 0, losses = 0, draws = 0;
let firehose = null;
let gameSessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
function configureAWS() {
const accessKey = document.getElementById('accessKey').value;
const secretKey = document.getElementById('secretKey').value;
if (!accessKey || !secretKey) {
alert('Access KeyとSecret Keyを入力してください');
return;
}
AWS.config.update({
accessKeyId: accessKey,
secretAccessKey: secretKey,
region: 'ap-northeast-1'
});
firehose = new AWS.Firehose();
document.getElementById('awsStatus').textContent = 'AWS設定完了';
document.getElementById('awsStatus').style.color = 'green';
}
function playGame(playerChoice) {
const choices = ['rock', 'paper', 'scissors'];
const computerChoice = choices[Math.floor(Math.random() * 3)];
let result;
if (playerChoice === computerChoice) {
result = 'draw';
draws++;
} else if (
(playerChoice === 'rock' && computerChoice === 'scissors') ||
(playerChoice === 'paper' && computerChoice === 'rock') ||
(playerChoice === 'scissors' && computerChoice === 'paper')
) {
result = 'win';
wins++;
} else {
result = 'lose';
losses++;
}
updateDisplay(playerChoice, computerChoice, result);
updateScore();
// ログをFirehoseに送信
sendLogToFirehose(playerChoice, computerChoice, result);
}
function sendLogToFirehose(playerChoice, computerChoice, result) {
if (!firehose) {
console.log('AWS未設定のため、ローカルログのみ:', {
timestamp: new Date().toISOString(),
sessionId: gameSessionId,
playerChoice: playerChoice,
computerChoice: computerChoice,
result: result
});
return;
}
const logData = {
timestamp: new Date().toISOString(),
sessionId: gameSessionId,
playerChoice: playerChoice,
computerChoice: computerChoice,
result: result,
userAgent: navigator.userAgent,
totalGames: wins + losses + draws
};
const params = {
DeliveryStreamName: '<your-stream-name>',
Record: {
Data: JSON.stringify(logData) + '\n'
}
};
firehose.putRecord(params, function(err, data) {
if (err) {
console.log('Firehose送信エラー:', err);
} else {
console.log('Firehose送信成功:', data);
}
});
}
function updateDisplay(player, computer, result) {
const choiceEmoji = {rock: '✊', paper: '✋', scissors: '✌️'};
const resultText = {win: '勝ち!', lose: '負け...', draw: 'あいこ'};
document.getElementById('result').innerHTML =
``;
}
function updateScore() {
document.getElementById('wins').textContent = wins;
document.getElementById('losses').textContent = losses;
document.getElementById('draws').textContent = draws;
}
</script>
</body>
</html>
-
DeliveryStreamName: '<your-stream-name>'を 03 で作成したストリーム名に置換します。 - ブラウザで html を開き、AWS 認証情報に 01 で発行した認証情報を入力して保存します
05. Data Firehose へのデータ送信
- ブラウザでゲームを実行し、コンソールログに「Firehose送信成功」が表示されることを確認
- 数分後、02 で作成した S3 バケットにデータが保存されていることを確認
06. Athena の初期設定
- 初めて利用する場合、クエリの結果の場所場所となる S3 バケットを指定
- 今回は 02 の S3 バケットに「athena-results」というフォルダを作成して保存場所に指定

07. Athena のテーブル作成
以下のクエリでテーブルを作成します。
S3 バケット名は 02 で作成したバケット名に置換してください。
CREATE EXTERNAL TABLE janken_game_logs (
log_data string
)
PARTITIONED BY (
year string,
month string,
day string,
hour string
)
STORED AS TEXTFILE
LOCATION 's3://[バケット名]/'
TBLPROPERTIES ('has_encrypted_data'='false');
以下のクエリでパーティション追加します。
S3 バケット名は 02 で作成したバケット名に置換してください。
year, month, hours は S3 バケットに作成されたプレフィックスに合わせてください。
ALTER TABLE janken_game_logs ADD PARTITION (
year='YYYY',
month='MM',
day='DD',
hour='HH'
) LOCATION 's3://[バケット名]/year=YYYY/month=MM/day=DD/hour=HH/';
08. データ分析
以下のクエリを実行し、ゲームの結果が表示されれば OK です。
SELECT
json_extract_scalar(log_data, '$.timestamp') as timestamp,
json_extract_scalar(log_data, '$.playerChoice') as playerChoice,
json_extract_scalar(log_data, '$.computerChoice') as computerChoice,
json_extract_scalar(log_data, '$.result') as result,
json_extract_scalar(log_data, '$.sessionId') as sessionId
FROM janken_game_logs
LIMIT 5;

以下のクエリでプレイヤーの選択傾向を分析できます。
SELECT
json_extract_scalar(log_data, '$.playerChoice') as playerChoice,
COUNT(*) as count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as percentage
FROM janken_game_logs
GROUP BY json_extract_scalar(log_data, '$.playerChoice')
ORDER BY count DESC;

以下のクエリで勝敗結果を分析できます。
SELECT
json_extract_scalar(log_data, '$.result') as result,
COUNT(*) as count,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as percentage
FROM janken_game_logs
GROUP BY json_extract_scalar(log_data, '$.result')
ORDER BY count DESC;

以下のクエリで選択肢別勝率を分析できます。
SELECT
json_extract_scalar(log_data, '$.playerChoice') as playerChoice,
COUNT(*) as total_games,
SUM(CASE WHEN json_extract_scalar(log_data, '$.result') = 'win' THEN 1 ELSE 0 END) as wins,
ROUND(
SUM(CASE WHEN json_extract_scalar(log_data, '$.result') = 'win' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
2
) as win_rate_percent
FROM janken_game_logs
GROUP BY json_extract_scalar(log_data, '$.playerChoice')
ORDER BY win_rate_percent DESC;

まとめ
今回はブラウザゲームの分析結果を Data Firehose に送信して Athena で分析してみました。
どなたかの参考になれば幸いです。
Discussion