Más contenido relacionado
La actualidad más candente (16)
Similar a 20171125 springfest snappydata (20)
Más de Masaki Yamakawa (10)
20171125 springfest snappydata
- 11. Apache Spark+分散インメモリーDB+独自機能
• Apache Sparkとインメモリーデータベースを統合し、独自機能を付加している
• ベースとなる製品はインメモリー処理が得意なので相性が良い
分散インメモリー
データベース
独自付加機能
カラム型データベース
予測分析処理
ロー型データベース
トランザクション
分散処理
フレームワーク
バッチ処理
分析処理
ストリーム処理
11
- 16. 特徴①:データアクセスのコード例
// SparkContextをラップしたSnappySessionを作成
val snappy = new org.apache.spark.sql.
SnappySession(spark.sparkContext)
// SQL、DataFrameを使用して新しいデータを作成
val filteredDf =
snappy.sql("SELECT * FROM SnappyTable WHERE …")
val newDf = filteredDf. ....
// 作成したデータを保存
newDf.write.insertInto("NewSnappyTable")
// データ読み込み
val df = spark.sqlContext.read.
format("com.databricks.spark.csv").
option("header", "true").load("hdfs://...")
df.createOrReplaceTempView("SparkTable")
// SparkSQL、DataFrameを使用して新しいデータを作成
val filteredDf =
spark.sql("SELECT * FROM SparkTable WHERE ...")
val newDf = filteredDf. ....
// 作成したデータを保存
newDf.write.
format("com.databricks.spark.csv").
option("header", "false").save("hdfs://...")
データ読み込み処理は不要
Sparkの場合 SnappyDataの場合
16
- 26. ストリームデータソース情報をテーブル定義で指定するだけ
ストリーミングデータソース
ストレージレベル(Spark設定)
CREATE STREAM TABLE CreditCardStream
(TxId long,
POS long,
CardNumber string,
TxAmount long
MerchantCode int,
Timestamp timestamp)
USING KAFKA_STREAM
OPTIONS
(storagelevel 'MEMORY_AND_DISK_SER_2',
rowConverter 'uls.snappy.KafkaToRowsConverter',
kafkaParams 'zookeeper.connect->localhost:2181;xx',
topics 'CreditCardTxStream');
KAFKA以外のストリーミングデータソース
TWITTER_STREAM
DIRECTKAFKA_STREAM
RABBITMQ_STREAM
SOCKET_STREAM
FILE_STREAM
ストリームデータRow変換クラス
ストリーミングデータソース毎の設定
26
- 27. StreamToRowsConverterを実装してテーブル形式に変換する
class KafkaToRowsConverter extends StreamToRowsConverter with Serializable {
override def toRows(message: Any): Seq[Row] = {
val ccTx: CreditCardStream = message.asInstanceOf[CreditCardStream]
Seq(Row.fromSeq(Seq(ccTx.getTxId,
ccTx.getPos,
ccTx.getCardNumber,
ccTx.getTxAmount,
ccTx.getMerchantCode,
ccTx.getTimestamp)))
}
}
ストリームテーブル
1行分のデータ
27
- 29. ContinuousQueryではWINDOWに含まれるデータのみ取得される
2 61 43
TxId POS
Card
Number
Tx
Amount
Merchant
Code
Timestamp
1 111 123456789 ¥10,000 AA 2017/11/05 10:10:01
2 222 777777777 ¥3,980 AA 2017/11/05 10:10:02
3 111 197654532 ¥5,130 BB 2017/11/05 10:10:08
2 61 43
2 61 43
5
5
5
TxId POS
Card
Number
Tx
Amount
Merchant
Code
Timestamp
3 111 197654532 ¥5,130 BB 2017/11/05 10:10:08
4 333 666666666 ¥323,456 AA 2017/11/05 10:10:15
TxId POS
Card
Number
Tx
Amount
Merchant
Code
Timestamp
4 333 666666666 ¥323,456 AA 2017/11/05 10:10:15
5 111 888888888 ¥1,980 BB 2017/11/05 10:10:13
6 111 123456789 ¥23,456 AA 2017/11/05 10:10:14
29
- 30. ストリームデータ処理のコード例
// ストリーム処理用のSnappyStreamingContextを作成
val snappy = new SnappyStreamingContext(sc, 10)
// Continuous Queryを登録
val creditCardTxStream : SchemaDStream = snappy.registerCQ(s"""
SELECT
TxId, POS, CardNumber, TxAmount, MerchantCode, Timestamp
FROM CreditCardStream
WINDOW
(DURATION 10 SECONDS, SLIDE 2 SECONDS)
WEHERE
MerchantCode='AA'
""")
// ストリームデータを処理
creditCardTxStream.foreachDataFrame(df => {
…
df.write.insertInto("CreditCardTxHistory")
…
}) 30
- 32. データの追加、更新、削除が可能
• 新しいデータセットを作成する際に全データを再作成する必要がない
ccBlackListStream.foreachRDD(rdd => {
val streamDS = rdd.toDS()
// CreditCardBlacklistより削除
streamDS.where("ACTION = 'DELETE'").write.deleteFrom("CreditCardBlacklist")
// CreditCardBlacklistへ追加・更新
streamDS.where("ACTION = 'INSERT'").write.putInto("CreditCardBlacklist")
})
creditCardTxStream.foreachRDD(rdd => {
val streamDS = rdd.toDS()
// blacklist tableのDataFrame作成
val ccBlackList = snappy.table("CreditCardBlacklist")
// JOINしたものをリジェクトトランザクションテーブルへ登録
val blackListedTxns = streamDS.join(ccBlackList, $"CardNumber" === $"CardNumber", "leftsemi")
val failedTx = blackListedTxns.select("TxId", "POS", "CardNumber", "MerchantCode", "Timestamp")
failedTx.write.insertInto("RejectedCardTx")
})
SnappySessionを使用し
通常のSQLで追加、更新、
削除することも可能
32
- 34. CREATE TABLE CreditCardBlacklist
(CardNumber CHAR(16) NOT NULL PRIMARY KEY,
CardType CHAR(1) NOT NULL,
ExpirationDate DATE NOT NULL,
… CHAR(3) ,
… CHAR(1) ,
… DATE ,
… DECIMAL(9,2))
USING ROW
OPTIONS
(PARTITION_BY 'CardNumber',
COLOCATE_WITH 'CardAccount',
REDUNDANCY '1',
EVICTION_BY 'LRUMEMSIZE 10240',
OVERFLOW 'true',
DISKSTORE 'LOCALSTORE',
PERSISTENCE 'ASYNC',
EXPIRE '86400');
CREATE TABLE CreditCardTxHistory
(TxId BIGINT ,
POS CHAR(2) ,
CardNumber CHAR(16) ,
TxAmount DECIMAL(15,2) ,
MerchantCode CHAR(2) ,
… DATE ,
… DECIMAL(9,2))
USING COLUMN
OPTIONS
(PARTITION_BY 'TxID',
COLOCATE_WITH 'CardAccount',
REDUNDANCY '1',
EVICTION_BY 'LRUMEMSIZE 10240',
OVERFLOW 'true',
DISKSTORE 'LOCALSTORE',
PERSISTENCE 'ASYNC');
RDBと大差ないDDLでテーブルを作成できる
• 分散インメモリーデータベースであるため、データ分散や永続化の設定が追加で必要
データベースエンジン データベースエンジン
データ分散設定 データ分散設定
永続化設定 永続化設定
Expireオプション
ローテーブル カラムテーブル
34
- 41. サンプリング技法を活用することでクエリー時間をさらに短縮
• データの平均や割合を出すのであれば、サンプリングが有効
• サンプリングしたデータを分析することで、通常のクエリーに比べて100分の1~10分の1にクエ
リー時間を短縮可能
¥182,531
¥132,712
¥79,521
¥12,903
¥0
¥20,000
¥40,000
¥60,000
¥80,000
¥100,000
¥120,000
¥140,000
¥160,000
¥180,000
¥200,000
111 222 333 444
POS
平均利用額
¥182,294
¥132,801
¥79,582
¥12,912
¥0
¥20,000
¥40,000
¥60,000
¥80,000
¥100,000
¥120,000
¥140,000
¥160,000
¥180,000
¥200,000
111 222 333 444
POS
平均利用額(サンプリング)
サンプリング
処理時間
10秒
処理時間
1.2秒
41
- 42. サンプリングの精度とクエリーのパフォーマンスを比較すると・・・
項目 標準SQL ケース1 ケース2 ケース3 ケース4 ケース5
誤差 - 0.20 0.05 0.20 0.30 0.20
信頼度 - 0.70 0.95 0.80 0.80 0.90
クエリー処理時間 10.0秒 1.2秒 1.4秒 1.3秒 1.2秒 1.1秒
0
2
4
6
8
10
12
クエリー処理時間
標準SQL ケース1
誤差:0.2
信頼度:0.7
ケース2
誤差:0.05
信頼度:0.95
ケース3
誤差:0.2
信頼度:0.8
ケース4
誤差:0.3
信頼度:0.8
ケース5
誤差:0.2
信頼度:0.9
42
- 43. 特定カラムのデータ分布を踏まえてサンプリングできる
• 一般的なDDLにサンプリングのための情報を指定する
CREATE SAMPLE TABLE
CreditCardTxHistorySample
ON CreditCardTxHistory
OPTIONS(
qcs 'POS, Year, Month',
fraction '0.03')
AS (SELECT * FROM
CreditCardTxHistory)
サンプルテーブル
43
ベーステーブル
CreditCardTxHistory サンプルテーブル
CreditCardTxHistorySample
サンプル
テーブル作成
Tx
Id
POS Year
Mont
h
Tx
Amount
…
1 111 2017 11 ¥10,000 …
2 222 2017 11 ¥3,980 …
3 111 2017 11 ¥5,130 …
4 222 2017 11 ¥323,456 …
5 111 2017 11 ¥1,980 …
6 111 2017 11 ¥23,456 …
Tx
Id
POS Year
Mon
th
Tx
Amount
…
1 111 2017 11 ¥10,000 …
2 222 2017 11 ¥3,980 …
5 111 2017 11 ¥1,980 …
指定したカラムのデータ分布を
踏まえてサンプルリングされる
- 45. TOP Kテーブル
• Max/Minのデータ検索ではTOPKテーブルを使用する
• 外れ値検出等で有効活用できる
CREATE TOPK TABLE MostUsedCreditCard
on CreditCardTxStream
OPTIONS (
key 'CardNumber',
timeInterval '60000ms’,
size '50’
frequencyCol 'TxAmount',
timeSeriesColumn 'Timestamp‘
)
1分間隔で利用金額の多い上位50件を収集する場合
CardNumber TxAmount …
666666666 ¥1,2345,678 …
197654532 ¥10,000,000 …
197654532 ¥5,048,600 …
・・・ ・・・ …
TOP Kテーブル
45
- 47. アプリケーションからのSnappyDataアクセス
• SnappyDataへ接続する場合は、一般的なJDBC/ODBC/ADO.NETプログラミングスタイルで
アクセスすることが可能
// SnappyData接続
val conn = DriverManager.getConnection("jdbc:snappydata://localhost:1527/APP")
// データ登録(Insert)
val psInsert = conn.
prepareStatement("INSERT INTO CreditCardBlacklist VALUES(?, ?, ?, ?, …)")
psInsert.setString(1, "1000200030004000")
psInsert.setBigDecimal(2, java.math.BigDecimal.valueOf(100.2))
…
psInsert.execute()
// データ取得(Select)
val psSelect = conn.prepareStatement(“SELECT * FROM CreditCardBlacklist WHERE CardNumber=?")
psSelect.setString(1, "1000200030004000")
ResultSet rs = psSelect.query()
// 切断
conn.close()
47
- 48. Springからも繋がります!
@Autowired
@Qualifier("snappyJdbc")
private JdbcTemplate snappyData;
@Component
public class SnappyDataConfiguration {
@Bean(name="snappyData")
public DataSource createDataSource() {
return DataSourceBuilder.create()
.driverClassName("io.snappydata.jdbc.ClientDriver")
.url("jdbc:snappydata://localhost:1527/APP")
.username("XXXXX").password("ZZZZZ")
.build();
}
@Bean(name="snappyJdbc")
public JdbcTemplate createJdbcTemplate(
@Qualifier("snappyData") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
…
}
48