About Me

My photo
Software Engineer at Starburst. Maintainer at Trino. Previously at LINE, Teradata, HPE.

2019-10-13

After Presto Conference Tokyo

7/11に開催されたPresto Conference Tokyo 2019について書こう書こうと思いつつ放置していたところ、ちょうど3ヶ月後の10/11にコミッターになったので、ご報告もかねて下書きを開きました。この記事では当日話そうと思ってスライドから削った部分や最近のコミュニティについて書きたいと思います。

現在Presto Software Foundation (PSF)とPresto Foundationという2つの組織があり、前者はPrestoを最初に作り始めたクリエイター達およびStarburstのメンバーを中心に、Arm Treasure DataVaradaQuboleなどその他にも多くの企業・開発者から支持されながら運営されています。後者はFacebookを中心にTwitter, Uber, Alibabaが支持していて、Linux Foundationにホストされることが先日発表されました。こう書くとどららを選ぶべきか悩むかもしれませんが、前者の方が開発の速度は早くコミュニティが非常に活発に動いてるので、特別な理由がなければPSF側のPrestoを使用することやコミュニティへの参加をお勧めします。Facebook側のリポジトリやSlackも見るようにしているのですが、対応が遅く残念な気持ちになります。メーリングリストは両者で同じアドレスが使用されているのですが、回答者の多くはPSFのコミュニティメンバーなのでSlackで直接質問するとすぐ回答を得られます。

PSFのSlackにはこちらのページにあるリンクから参加できます。
https://prestosql.io/slack.html

チャンネルは結構多くて戸惑いそうですが、個人的にお勧めするチャンネルは以下の通りです。

  • #troubleshooting #generalで質問しても問題ないのですがトラブル等はこちらで質問すると素早く回答を得ることができます
  • #community-announcement ミートアップなどの情報がポストされます
  • #dev 開発に興味がある方はぜひ!
  • #general-jp 日本語で気軽に話せるチャンネルです

実際に開発に参加しなくても、もっと日本からコミュニティに参加してくれる方が増えてくれるととても嬉しいです。コードは書かずにSlackで議論に参加しているだけのメンバーもいますが、多数のコネクタを1リポジトリで管理していることもあり、そういったフィードバックはとても貴重に扱われます。

その他のリンクとしては以下のようなものがあります。

今更になりますがPresto Conference Tokyo 2019を企画してくださったArm Treasure Dataの方々、参加者のみなさん、HadoopのIssueを進めてくださったお二方、どうも有り難うございました。また来年も開催できると良いですね。

2019-08-30

Everything becomes F

すべてがFになる」の後半を読んでいたら、平日にも関わらず朝の4時半頃まで起きてしまいました...。今まで読んだ森博嗣さんの作品の中で最も面白かったです。これがデビュー作というのが凄い。次は百年シリーズを読もうと思っていたのですが、S&Mシリーズを順に読んでみることにします。最近話題になっている「三体」も買ってあるので楽しみです。



作中のプログラミングのシーンを読んでいて、数年前に電車に乗っていた時、隣にいた女性が子どもに「片手でいくつまで数をかぞえられる?お母さんは31まで数えられるよ」と言って、二進数を教えていたのをふと思い出しました。あの人はプログラマーだったかが気になります。
右手を例にあげると、手前に向けたグーの状態が00000で0、親指を立てると00001で1、次に親指を戻して人差し指を立てると00010で2という具合で2^5 - 1である31まで数えることができます。

00000→0
00001→1
00010→2
00011→3
00100→4
...
11110→30
11111→31

この方法を使うと両手で1023(2^10 - 1)まで数えることができます。数学としては当たり前であっても両手で自分の手に約1000個の数字が収まるというのはなんだか不思議な感じがします。

2019-07-28

After the Matinee

7月に休みをとって宮城の松島海岸に1泊2日で旅行してきました。いつも一人で旅行に行くときは本を持っていくのですが、今回は本屋で目にとまった「マチネの終わりに」と共に。恋愛小説を読むのは初めてでしたが、いわゆるドロドロとした内容で読んでいて辛い部分もありつつも先が気になる展開が続き、結局初日の夕ご飯前には読み切ってしまいました。作中で何度か出てくる「未来は常に過去を変えている」という文章がとても心に残っています。良かった思い出がふとしたきっかけで悲しい思い出になったり、その逆もあったりしますもんね。ギタリストと国際ジャーナリストの恋愛ということもあり、芸術、イラク情勢、原爆やサブプライムローンなど様々な話題が散りばめられていて、読んだあとに自分でもう一度学びたいと感じる本でした。11月1日には映画が公開される予定とのことで、できれば初日に観に行きたいなぁと思っています。


松島湾

福浦橋

福浦島

遊覧船からの眺め
松島自体は初日は小雨が降っていて少し残念でしたが綺麗なアジサイの写真が撮れて満足です。行きの新幹線と仙台駅でご飯を食べ過ぎたこともあり早めにホテルへチェックインしてのんびりしてました。2日目は朝露天風呂に入っていたら松島湾が眩し過ぎて目がちゃんと開かないぐらいには天気が良かったです。チェックアウトしてからは海岸通りをぶらぶらして福浦島に向かいました。木が生い茂っていてちょっとしたジャングルみたいで散策を楽しめました。松島湾を1周する遊覧船に乗ろうと思ってたのですが、受付の方に仙台方面に戻るのであれば電車が少ないので塩川港まで行くルートがお勧めですよと教えていただき、そっちに乗ってみました。最後に仙台駅でお寿司を食べて新幹線で帰宅です。お寿司以外にもたくさん美味しいもの、牛タン、穴子、牡蠣、笹かまぼこ、ずんだジェラート、ずんだシェイクなどなどを食べて終始満腹でした。

2019-05-17

The Garden of words

お花見シーズンぶりに、またもやお昼にオフィスを抜け出して新宿御苑に行ってきました。たまたま「森のおもちゃ美術館」というイベントがやっていて、幼稚園児ぐらいの子達が無邪気にはしゃいでる姿になんだか癒されました。いつも新宿門から入って奥側のバラ花壇までは行かないんですが、そのイベントに釣られて行ってみたところ綺麗な花がたくさん咲いてました。1番上の白いふわふわしたやつが綺麗だったので名札(?)も撮って帰って家で調べたところ、これは作者がつけたあだ名みたいなやつだったらしく、正式な名前が分からず...。

帰りは新宿門まで日本庭園側を歩いていたら、老夫婦が結構な量の葉っぱをむしってカバンに入れていて、なんだろうと思ってよく見てみたら茶葉でした。あれだけ持って帰るってことはきっと飲むんだろうなぁ。新宿御苑の茶葉ってどんな味するんだろう。

最後の2枚は葉桜とさくらんぼです。一面が青々として綺麗でした。閑散としているなか葉桜を眺めるのも良いですねぇ。










2019-04-30

Machine Learning Connector in Presto

This is quick tutorial for presto-ml connector. The connector isn't maintenanced actively and the supported model is only SVM.

You can see below sample query in the test directory. As the same as Teradata Aster and BigQuery ML, there're two kinds of functions.

  • learn_classifier: receives training data and generates the model
  • classify: receives the model & test data and returns the prediction


SELECT classify(features(1, 2), model)
FROM (
 SELECT learn_classifier(labels, features) AS model
 FROM (
  VALUES (1, features(1, 2))) t(labels, features)
) t2
→ 1

SELECT classify(features(1, 2), model)
FROM (
 SELECT learn_classifier(labels, features) AS model
 FROM (
  VALUES ('cat', features(1, 2))) t(labels, features)
) t2
→ 'cat'

Let's try using Iris data sets.
CREATE TABLE iris (
  id int
, sepal_length double
, sepal_width double
, petal_length double
, petal_width double
, species varchar
)

INSERT INTO iris VALUES 
(1, 5.1, 3.5, 1.4, 0.2, 'Iris-setosa'),
(2, 4.9, 3, 1.4, 0.2, 'Iris-setosa'),
(3, 4.7, 3.2, 1.3, 0.2, 'Iris-setosa'),
(4, 4.6, 3.1, 1.5, 0.2, 'Iris-setosa'),
(5, 5, 3.6, 1.4, 0.2, 'Iris-setosa'),
(6, 5.4, 3.9, 1.7, 0.4, 'Iris-setosa'),
(7, 4.6, 3.4, 1.4, 0.3, 'Iris-setosa'),
(8, 5, 3.4, 1.5, 0.2, 'Iris-setosa'),
(9, 4.4, 2.9, 1.4, 0.2, 'Iris-setosa'),
(10, 4.9, 3.1, 1.5, 0.1, 'Iris-setosa'),
(11, 5.4, 3.7, 1.5, 0.2, 'Iris-setosa'),
(12, 4.8, 3.4, 1.6, 0.2, 'Iris-setosa'),
(13, 4.8, 3, 1.4, 0.1, 'Iris-setosa'),
(14, 4.3, 3, 1.1, 0.1, 'Iris-setosa'),
(15, 5.8, 4, 1.2, 0.2, 'Iris-setosa'),
(16, 5.7, 4.4, 1.5, 0.4, 'Iris-setosa'),
(17, 5.4, 3.9, 1.3, 0.4, 'Iris-setosa'),
(18, 5.1, 3.5, 1.4, 0.3, 'Iris-setosa'),
(19, 5.7, 3.8, 1.7, 0.3, 'Iris-setosa'),
(20, 5.1, 3.8, 1.5, 0.3, 'Iris-setosa'),
(21, 5.4, 3.4, 1.7, 0.2, 'Iris-setosa'),
(22, 5.1, 3.7, 1.5, 0.4, 'Iris-setosa'),
(23, 4.6, 3.6, 1, 0.2, 'Iris-setosa'),
(24, 5.1, 3.3, 1.7, 0.5, 'Iris-setosa'),
(25, 4.8, 3.4, 1.9, 0.2, 'Iris-setosa'),
(26, 5, 3, 1.6, 0.2, 'Iris-setosa'),
(27, 5, 3.4, 1.6, 0.4, 'Iris-setosa'),
(28, 5.2, 3.5, 1.5, 0.2, 'Iris-setosa'),
(29, 5.2, 3.4, 1.4, 0.2, 'Iris-setosa'),
(30, 4.7, 3.2, 1.6, 0.2, 'Iris-setosa'),
(31, 4.8, 3.1, 1.6, 0.2, 'Iris-setosa'),
(32, 5.4, 3.4, 1.5, 0.4, 'Iris-setosa'),
(33, 5.2, 4.1, 1.5, 0.1, 'Iris-setosa'),
(34, 5.5, 4.2, 1.4, 0.2, 'Iris-setosa'),
(35, 4.9, 3.1, 1.5, 0.1, 'Iris-setosa'),
(36, 5, 3.2, 1.2, 0.2, 'Iris-setosa'),
(37, 5.5, 3.5, 1.3, 0.2, 'Iris-setosa'),
(38, 4.9, 3.1, 1.5, 0.1, 'Iris-setosa'),
(39, 4.4, 3, 1.3, 0.2, 'Iris-setosa'),
(40, 5.1, 3.4, 1.5, 0.2, 'Iris-setosa'),
(41, 5, 3.5, 1.3, 0.3, 'Iris-setosa'),
(42, 4.5, 2.3, 1.3, 0.3, 'Iris-setosa'),
(43, 4.4, 3.2, 1.3, 0.2, 'Iris-setosa'),
(44, 5, 3.5, 1.6, 0.6, 'Iris-setosa'),
(45, 5.1, 3.8, 1.9, 0.4, 'Iris-setosa'),
(46, 4.8, 3, 1.4, 0.3, 'Iris-setosa'),
(47, 5.1, 3.8, 1.6, 0.2, 'Iris-setosa'),
(48, 4.6, 3.2, 1.4, 0.2, 'Iris-setosa'),
(49, 5.3, 3.7, 1.5, 0.2, 'Iris-setosa'),
(50, 5, 3.3, 1.4, 0.2, 'Iris-setosa'),
(51, 7, 3.2, 4.7, 1.4, 'Iris-versicolor'),
(52, 6.4, 3.2, 4.5, 1.5, 'Iris-versicolor'),
(53, 6.9, 3.1, 4.9, 1.5, 'Iris-versicolor'),
(54, 5.5, 2.3, 4, 1.3, 'Iris-versicolor'),
(55, 6.5, 2.8, 4.6, 1.5, 'Iris-versicolor'),
(56, 5.7, 2.8, 4.5, 1.3, 'Iris-versicolor'),
(57, 6.3, 3.3, 4.7, 1.6, 'Iris-versicolor'),
(58, 4.9, 2.4, 3.3, 1, 'Iris-versicolor'),
(59, 6.6, 2.9, 4.6, 1.3, 'Iris-versicolor'),
(60, 5.2, 2.7, 3.9, 1.4, 'Iris-versicolor'),
(61, 5, 2, 3.5, 1, 'Iris-versicolor'),
(62, 5.9, 3, 4.2, 1.5, 'Iris-versicolor'),
(63, 6, 2.2, 4, 1, 'Iris-versicolor'),
(64, 6.1, 2.9, 4.7, 1.4, 'Iris-versicolor'),
(65, 5.6, 2.9, 3.6, 1.3, 'Iris-versicolor'),
(66, 6.7, 3.1, 4.4, 1.4, 'Iris-versicolor'),
(67, 5.6, 3, 4.5, 1.5, 'Iris-versicolor'),
(68, 5.8, 2.7, 4.1, 1, 'Iris-versicolor'),
(69, 6.2, 2.2, 4.5, 1.5, 'Iris-versicolor'),
(70, 5.6, 2.5, 3.9, 1.1, 'Iris-versicolor'),
(71, 5.9, 3.2, 4.8, 1.8, 'Iris-versicolor'),
(72, 6.1, 2.8, 4, 1.3, 'Iris-versicolor'),
(73, 6.3, 2.5, 4.9, 1.5, 'Iris-versicolor'),
(74, 6.1, 2.8, 4.7, 1.2, 'Iris-versicolor'),
(75, 6.4, 2.9, 4.3, 1.3, 'Iris-versicolor'),
(76, 6.6, 3, 4.4, 1.4, 'Iris-versicolor'),
(77, 6.8, 2.8, 4.8, 1.4, 'Iris-versicolor'),
(78, 6.7, 3, 5, 1.7, 'Iris-versicolor'),
(79, 6, 2.9, 4.5, 1.5, 'Iris-versicolor'),
(80, 5.7, 2.6, 3.5, 1, 'Iris-versicolor'),
(81, 5.5, 2.4, 3.8, 1.1, 'Iris-versicolor'),
(82, 5.5, 2.4, 3.7, 1, 'Iris-versicolor'),
(83, 5.8, 2.7, 3.9, 1.2, 'Iris-versicolor'),
(84, 6, 2.7, 5.1, 1.6, 'Iris-versicolor'),
(85, 5.4, 3, 4.5, 1.5, 'Iris-versicolor'),
(86, 6, 3.4, 4.5, 1.6, 'Iris-versicolor'),
(87, 6.7, 3.1, 4.7, 1.5, 'Iris-versicolor'),
(88, 6.3, 2.3, 4.4, 1.3, 'Iris-versicolor'),
(89, 5.6, 3, 4.1, 1.3, 'Iris-versicolor'),
(90, 5.5, 2.5, 4, 1.3, 'Iris-versicolor'),
(91, 5.5, 2.6, 4.4, 1.2, 'Iris-versicolor'),
(92, 6.1, 3, 4.6, 1.4, 'Iris-versicolor'),
(93, 5.8, 2.6, 4, 1.2, 'Iris-versicolor'),
(94, 5, 2.3, 3.3, 1, 'Iris-versicolor'),
(95, 5.6, 2.7, 4.2, 1.3, 'Iris-versicolor'),
(96, 5.7, 3, 4.2, 1.2, 'Iris-versicolor'),
(97, 5.7, 2.9, 4.2, 1.3, 'Iris-versicolor'),
(98, 6.2, 2.9, 4.3, 1.3, 'Iris-versicolor'),
(99, 5.1, 2.5, 3, 1.1, 'Iris-versicolor'),
(100, 5.7, 2.8, 4.1, 1.3, 'Iris-versicolor'),
(101, 6.3, 3.3, 6, 2.5, 'Iris-virginica'),
(102, 5.8, 2.7, 5.1, 1.9, 'Iris-virginica'),
(103, 7.1, 3, 5.9, 2.1, 'Iris-virginica'),
(104, 6.3, 2.9, 5.6, 1.8, 'Iris-virginica'),
(105, 6.5, 3, 5.8, 2.2, 'Iris-virginica'),
(106, 7.6, 3, 6.6, 2.1, 'Iris-virginica'),
(107, 4.9, 2.5, 4.5, 1.7, 'Iris-virginica'),
(108, 7.3, 2.9, 6.3, 1.8, 'Iris-virginica'),
(109, 6.7, 2.5, 5.8, 1.8, 'Iris-virginica'),
(110, 7.2, 3.6, 6.1, 2.5, 'Iris-virginica'),
(111, 6.5, 3.2, 5.1, 2, 'Iris-virginica'),
(112, 6.4, 2.7, 5.3, 1.9, 'Iris-virginica'),
(113, 6.8, 3, 5.5, 2.1, 'Iris-virginica'),
(114, 5.7, 2.5, 5, 2, 'Iris-virginica'),
(115, 5.8, 2.8, 5.1, 2.4, 'Iris-virginica'),
(116, 6.4, 3.2, 5.3, 2.3, 'Iris-virginica'),
(117, 6.5, 3, 5.5, 1.8, 'Iris-virginica'),
(118, 7.7, 3.8, 6.7, 2.2, 'Iris-virginica'),
(119, 7.7, 2.6, 6.9, 2.3, 'Iris-virginica'),
(120, 6, 2.2, 5, 1.5, 'Iris-virginica'),
(121, 6.9, 3.2, 5.7, 2.3, 'Iris-virginica'),
(122, 5.6, 2.8, 4.9, 2, 'Iris-virginica'),
(123, 7.7, 2.8, 6.7, 2, 'Iris-virginica'),
(124, 6.3, 2.7, 4.9, 1.8, 'Iris-virginica'),
(125, 6.7, 3.3, 5.7, 2.1, 'Iris-virginica'),
(126, 7.2, 3.2, 6, 1.8, 'Iris-virginica'),
(127, 6.2, 2.8, 4.8, 1.8, 'Iris-virginica'),
(128, 6.1, 3, 4.9, 1.8, 'Iris-virginica'),
(129, 6.4, 2.8, 5.6, 2.1, 'Iris-virginica'),
(130, 7.2, 3, 5.8, 1.6, 'Iris-virginica'),
(131, 7.4, 2.8, 6.1, 1.9, 'Iris-virginica'),
(132, 7.9, 3.8, 6.4, 2, 'Iris-virginica'),
(133, 6.4, 2.8, 5.6, 2.2, 'Iris-virginica'),
(134, 6.3, 2.8, 5.1, 1.5, 'Iris-virginica'),
(135, 6.1, 2.6, 5.6, 1.4, 'Iris-virginica'),
(136, 7.7, 3, 6.1, 2.3, 'Iris-virginica'),
(137, 6.3, 3.4, 5.6, 2.4, 'Iris-virginica'),
(138, 6.4, 3.1, 5.5, 1.8, 'Iris-virginica'),
(139, 6, 3, 4.8, 1.8, 'Iris-virginica'),
(140, 6.9, 3.1, 5.4, 2.1, 'Iris-virginica'),
(141, 6.7, 3.1, 5.6, 2.4, 'Iris-virginica'),
(142, 6.9, 3.1, 5.1, 2.3, 'Iris-virginica'),
(143, 5.8, 2.7, 5.1, 1.9, 'Iris-virginica'),
(144, 6.8, 3.2, 5.9, 2.3, 'Iris-virginica'),
(145, 6.7, 3.3, 5.7, 2.5, 'Iris-virginica'),
(146, 6.7, 3, 5.2, 2.3, 'Iris-virginica'),
(147, 6.3, 2.5, 5, 1.9, 'Iris-virginica'),
(148, 6.5, 3, 5.2, 2, 'Iris-virginica'),
(149, 6.2, 3.4, 5.4, 2.3, 'Iris-virginica'),
(150, 5.9, 3, 5.1, 1.8, 'Iris-virginica');

In this data sets, species is a label and sepal_length, sepal_width and so on are features.
SELECT
 learn_classifier(species, features(sepal_length, sepal_width, petal_length, petal_width)) AS model
FROM iris
                      model                   
-------------------------------------------------
 3c 43 6c 61 73 73 69 66 69 65 72 28 76 61 72 63
 68 61 72 29 3e                               

This features function gives the number (0~9) to each arguments and returns it as map types. It returns unexpected parameters if the arguments number is over 10.
SELECT features(-100, 100);
        _col0     
---------------------
 {0=-100.0, 1=100.0}

SELECT features(1,2,3,4,5,6,7,8,9,10,11);
→Unexpected parameters

Next, let's try to get the prediction using classify function. features(5.9, 3, 5.1, 1.8) is final rows above the insert statements. I used it for clarify. We can get expected result 'Iris-virginica', the same as inserted data.
SELECT classify(features(5.9, 3, 5.1, 1.8), model)
FROM (
SELECT
 learn_classifier(species, features(sepal_length, sepal_width, petal_length, petal_width)) AS model
FROM iris
) t
     _col0   
----------------
 Iris-virginica


Though we want to store the machine learning model in a storage, current learn_classifier doesn't allow it. It uses original type in the connector.
CREATE TABLE learn_classifier_model AS
 SELECT learn_classifier(labels, features) AS model
 FROM (
  VALUES ('cat', features(1, 2))) t(labels, features)
;
→ Unsupported type: Classifier(varchar)

If you're interested in presto-ml, you can address this issue https://github.com/prestosql/presto/issues/662.

2019-04-20

INSERT OVERWRITE in Presto

If you are hive user and ETL developer, you may see a lot of INSERT OVERWRITE. Though it's not yet documented, Presto also supports OVERWRITE mode for partitioned table.

Currently, there are 3 modes, OVERWRITE, APPEND and ERROR.

OVERWRITE overwrites existing partition.
APPEND appends rows in existing partition.
ERROR fails when the partition already exists.

You can change the mode by set session command.
set session hive.insert_existing_partitions_behavior = 'overwrite';
set session hive.insert_existing_partitions_behavior = 'append';
set session hive.insert_existing_partitions_behavior = 'error';

The enhanced feature for an unpartitioned table is ongoing in this PR (https://github.com/prestosql/presto/pull/648) by James Xu.

The enhancement was merged as https://github.com/prestosql/presto/pull/924

2019-03-18

MSCK in Trino

Presto SQL release 304 contains new procedure system.sync_partition_metadata() developed by @luohao.  This is similar to hive's MSCK REPAIR TABLE.

Document about Hive Connector Procedures is https://prestosql.io/docs/current/connector/hive.html#procedures

The syntax is `system.sync_partition_metadata(schema_name, table_name, mode)`. The supported mode are add, drop and full. Example query is

  • call system.sync_partition_metadata('default', 'test_partition', 'add');
  • call system.sync_partition_metadata('default', 'test_partition', 'drop');
  • call system.sync_partition_metadata('default', 'test_partition', 'full');

# Mode DROP
hive> create table default.test_partition (c1 int) partitioned by (dt string);
hive> insert overwrite table default.test_partition partition(dt = '20190101') values (1);
hive> dfs -mv hdfs://hadoop-master:9000/user/hive/warehouse/test_partition/dt=20190101 /tmp/;
hive> show partitions default.test_partition;
dt=20190101

presto> use hive.default;
presto> call system.sync_partition_metadata('default', 'test_partition', 'drop');

hive> show partitions default.test_partition;
→ Empty

# Mode ADD
hive> dfs -mv /tmp/dt=20190101 hdfs://hadoop-master:9000/user/hive/warehouse/test_partition/;

presto> call system.sync_partition_metadata('default', 'test_partition', 'add');

hive>  show partitions default.test_partition;
dt=20190101

# Mode FULL performs both DROP and ADD. 

2019-01-04

Try Apache Griffin

Currently, Griffin doesn't provide the binary, therefore you need to build it yourself. It's not difficult though. I tried it on hortonworks:sandbox-hdp container. Even if you're using default environment, additional steps are just adding Spark on Ambari and installing maven.

# Add Spark
login ambari (http://localhost:8080/#/login)
Spark2 -> Service Actions -> Start

# Login to hortonworks:sandbox-hdp using bash
docker exec -it sandbox-hdp bash

# Install maven if not installed on there
wget http://ftp.riken.jp/net/apache/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz
tar -xvf apache-maven-3.6.0-bin.tar.gz
cd apache-maven-3.6.0
mv apache-maven-3.6.0 /opt/apache-maven-3.6.0
vi /etc/environment
  M2_HOME="/opt/apache-maven-3.6.0"
  export PATH=$M3:$PATH

sudo update-alternatives --install "/usr/bin/mvn" "mvn" "/opt/apache-maven-3.6.0/bin/mvn" 0
sudo update-alternatives --set mvn /opt/apache-maven-3.6.0/bin/mvn

# Install griffin (http://griffin.apache.org/docs/quickstart.html)
wget https://www.apache.org/dist/incubator/griffin/0.3.0-incubating/griffin-0.3.0-incubating-source-release.zip
unzip griffin-0.3.0-incubating-source-release.zip
cd griffin-0.3.0-incubating
mvn clean install
  It takes about few minutes (my case was 14 min) and the size will be 660MB.
mv measure/target/measure-0.3.0-incubating.jar /usr/local/griffin-measure.jar

# Prepare demo data
wget --recursive --no-parent http://griffin.apache.org/data/batch
cd griffin.apache.org/data/batch
chmod +x *.sh
./gen_demo_data.sh

hive
CREATE EXTERNAL TABLE `demo_src`(
  `id` bigint,
  `age` int,
  `desc` string)
PARTITIONED BY (
  `dt` string,
  `hour` string)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY '|'
;

CREATE EXTERNAL TABLE `demo_tgt`(
  `id` bigint,
  `age` int,
  `desc` string)
PARTITIONED BY (
  `dt` string,
  `hour` string)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY '|'
;


LOAD DATA LOCAL INPATH 'demo_src' INTO TABLE demo_src PARTITION (dt='20180912',hour='09');
LOAD DATA LOCAL INPATH 'demo_tgt' INTO TABLE demo_tgt PARTITION (dt='20180912',hour='09');

# Create config file
vi env.json
{
  "spark": {
    "log.level": "WARN"
  },
  "sinks": [
    {
      "type": "console"
    },
    {
      "type": "hdfs",
      "config": {
        "path": "hdfs:///griffin/persist"
      }
    },
    {
      "type": "elasticsearch",
      "config": {
        "method": "post",
        "api": "http://es:9200/griffin/accuracy"
      }
    }
  ]
}


vi dq.json
{
  "name": "batch_accu",
  "process.type": "batch",
  "data.sources": [
    {
      "name": "src",
      "baseline": true,
      "connectors": [
        {
          "type": "hive",
          "version": "1.2",
          "config": {
            "database": "default",
            "table.name": "demo_src"
          }
        }
      ]
    }, {
      "name": "tgt",
      "connectors": [
        {
          "type": "hive",
          "version": "1.2",
          "config": {
            "database": "default",
            "table.name": "demo_tgt"
          }
        }
      ]
    }
  ],
  "evaluate.rule": {
    "rules": [
      {
        "dsl.type": "griffin-dsl",
        "dq.type": "accuracy",
        "out.dataframe.name": "accu",
        "rule": "src.id = tgt.id AND src.age = tgt.age AND src.desc = tgt.desc",
        "details": {
          "source": "src",
          "target": "tgt",
          "miss": "miss_count",
          "total": "total_count",
          "matched": "matched_count"
        },
        "out": [
          {
            "type": "metric",
            "name": "accu"
          },
          {
            "type": "record",
            "name": "missRecords"
          }
        ]
      }
    ]
  },
  "sinks": ["CONSOLE", "HDFS"]
}

# Run !
spark-submit --class org.apache.griffin.measure.Application --master yarn --deploy-mode client --queue default --driver-memory 1g --executor-memory 1g --num-executors 2 /usr/local/griffin-measure.jar /env.json /dq.json

# Result
data source timeRanges: src -> (1544668358323, 1544668358323], tgt -> (1544668358323, 1544668358323]
[1544668358323] batch_accu start: application_1544490410222_0011
batch_accu [1544668358323] metrics:
{"name":"batch_accu","tmst":1544668358323,"value":{"total_count":125000,"miss_count":512,"matched_count":124488}}

# Check above miss_count manually
select
 count(src.id) as total_count
 ,sum(if(tgt.id is null, 1, 0)) as miss_count
 ,sum(if(tgt.id is not null, 1, 0)) as matched_count
from demo_src src
left outer join demo_tgt tgt
on src.id = tgt.id AND src.age = tgt.age AND src.desc = tgt.desc
;

total_count, miss_count, matched_count
125000, 512, 124488

# Generated files on HDFS
[root@sandbox-hdp /]# hdfs dfs -ls /griffin/persist/batch_accu/1544668358323
Found 5 items
-rw-r--r--   1 root hdfs          0 2018-12-13 02:33 /griffin/persist/batch_accu/1544668358323/_FINISH
-rw-r--r--   1 root hdfs        137 2018-12-13 02:33 /griffin/persist/batch_accu/1544668358323/_LOG
-rw-r--r--   1 root hdfs        113 2018-12-13 02:33 /griffin/persist/batch_accu/1544668358323/_METRICS
-rw-r--r--   1 root hdfs         30 2018-12-13 02:32 /griffin/persist/batch_accu/1544668358323/_START

-rw-r--r--   1 root hdfs      44543 2018-12-13 02:33 /griffin/persist/batch_accu/1544668358323/missRecords


hdfs dfs -cat /griffin/persist/batch_accu/1544668358323/_FINISH
(empty)

hdfs dfs -cat /griffin/persist/batch_accu/1544668358323/_LOG
================ log of Thu Dec 16 02:32:38 UTC 2018 ================
--- Thu Dec 16 02:33:18 UTC 2018 ---
process using time: 40444 ms


hdfs dfs -cat /griffin/persist/batch_accu/1544668358323/_METRICS
{"name":"batch_accu","tmst":1544668358323,"value":{"total_count":125000,"miss_count":512,"matched_count":124488}}


hdfs dfs -cat /griffin/persist/batch_accu/1544668358323/_START
application_1544490410222_0011



hdfs dfs -cat /griffin/persist/batch_accu/1544668358323/missRecords
{"id":124,"age":1273,"desc":"1273","dt":"20180912","hour":"09","__tmst":1544668358323}
{"id":124,"age":1065,"desc":"1065","dt":"20180912","hour":"09","__tmst":1544668358323}
{"id":124,"age":1798,"desc":"1798","dt":"20180912","hour":"09","__tmst":1544668358323}