デイリーのアクセスを取得
次に、デイリーのアクセスを取得するコードです。取得するColumnFamilyやColumnが違っているくらいで、基本的にはアワリーの場合と変わった部分はありません。
// デイリーのアクセスを取得する public List<Access> getDailyCount(String domain, String path, Calendar startDay, Calendar endDay) throws IOException { // Scanの作成 Scan scan; String reversedDomain = reverseDomain(domain); if (path != null) { byte[] row = createRow(reversedDomain, path); scan = new Scan(row, row); } else { byte[] prefix = Bytes.toBytes(reversedDomain); scan = new Scan(prefix); scan.setFilter(new PrefixFilter(prefix)); } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); // startDayとendDayから取得したいColumnを指定 Calendar cal = (Calendar) startDay.clone(); while (cal.before(endDay)) { scan.addColumn(DAILY_COLUMN_FAMILY, Bytes.toBytes(sdf.format(cal.getTime()))); cal.add(Calendar.DAY_OF_MONTH, 1); } // 結果の取得 List<Access> ret = new ArrayList<Access>(); HTableInterface table = hTablePool.getTable(TABLE); try { ResultScanner scanner = table.getScanner(scan); for (Result result : scanner) { String[] domainAndPath = extractDomainAndPath(result.getRow()); for (Map.Entry<byte[], byte[]> entry: result.getFamilyMap(DAILY_COLUMN_FAMILY).entrySet()) { byte[] qualifier = entry.getKey(); byte[] value = entry.getValue(); // 時間 Calendar time = Calendar.getInstance(); time.setTime(sdf.parse(Bytes.toString(qualifier))); // Accessオブジェクトの作成 Access access = new Access(); access.setTime(time); access.setDomain(reverseDomain(domainAndPath[0])); access.setPath(domainAndPath[1]); access.setCount(Bytes.toLong(value)); ret.add(access); } } } catch (ParseException e) { // 省略 } finally { table.close(); } return ret; }
トータルのアクセスを取得
最後に、トータルのアクセスを取得するコードです。これも、基本的にはアワリーやデイリーのコードと同様になります。
ただしトータルのアクセスの場合、年月日などの情報がないので、Columnを限定する処理はありません。
// トータルのアクセスを取得する public List<Access> getTotalCount(String domain, String path) throws IOException { // Scanの作成 Scan scan; String reversedDomain = reverseDomain(domain); if (path != null) { byte[] row = createRow(reversedDomain, path); scan = new Scan(row, row); } else { byte[] prefix = Bytes.toBytes(reversedDomain); scan = new Scan(prefix); scan.setFilter(new PrefixFilter(prefix)); } scan.addFamily(TOTAL_COLUMN_FAMILY); // ColumnFamilyを限定する // 結果の取得 List<Access> ret = new ArrayList<Access>(); HTableInterface table = hTablePool.getTable(TABLE); try { ResultScanner scanner = table.getScanner(scan); for (Result result : scanner) { String[] domainAndPath = extractDomainAndPath(result.getRow()); // Accessオブジェクトの作成 Access access = new Access(); access.setDomain(reverseDomain(domainAndPath[0])); access.setPath(domainAndPath[1]); access.setCount(Bytes.toLong(result.getValue(TOTAL_COLUMN_FAMILY, HConstants.EMPTY_BYTE_ARRAY))); ret.add(access); } } finally { table.close(); } return ret; }
まとめ
今回は、HBaseを使って簡易アクセス解析サービスを作成しました。前回に比べて、比較的シンプルで分かりやすかったのではないでしょうか。次回も引き続き、HBaseを使ったアプリケーションの別のケーススタディを紹介する予定です。
また、株式会社サイバーエージェントでは、Hadoop/HBaseエンジニアを募集しています。ご興味のある方はこちらからエントリーしていただければと思います。エンジニア>R&Dエンジニア>R&Dエンジニアを選択しエントリーしていただければ幸いです。