InfluxDBとGrafanaとfluentdで、twitterデータのリアルタイム集計・可視化

  • 161
    Like
  • 0
    Comment
More than 1 year has passed since last update.

この記事は、以下の記事を参考に書かれました。

InfluxDB を10分だけ触ってみた
Grafana on InfluxDB をちょっとだけ触ってみた

以下の内容はInfluxDB v0.5.4 [2014-04-02 release]について記載しています。

InfluxDBのセットアップ

install

  • OS X
$ brew update
$ brew install influxdb
$ influxdb start

常時起動するなら

$ ln -sfv /usr/local/opt/influxdb/*.plist ~/Library/LaunchAgents
$ brew services start influxdb
  • Debian系
$ wget http://s3.amazonaws.com/influxdb/influxdb_latest_amd64.deb
$ sudo dpkg -i influxdb_latest_amd64.deb
  • RedHat系
$ wget http://s3.amazonaws.com/influxdb/influxdb-latest-1.x86_64.rpm
$ sudo rpm -ivh influxdb-latest-1.x86_64.rpm

WebUI

http://localhost:8083/ でWebUIが見れます。
デフォルトはroot/rootで入れます。

InfluxDB WebUI login

Create Database

WebUIからも出来るのですが、rubyのライブラリからやってみます。

$ gem install influxdb
$ pry
require 'influxdb'
=> true
influxdb = InfluxDB::Client.new  :username => 'root', :password => 'root'
=> #<InfluxDB::Client:0x007fb424481ec8
 @async=false,
 @hosts=["localhost"],
 @initial_delay=0.01,
 @max_delay=30,
 @open_timeout=5,
 @password="root",
 @port=8086,
 @read_timeout=300,
 @time_precision="s",
 @use_ssl=false,
 @username="root">
influxdb.create_database('qiitademo')
=> #<Net::HTTPCreated 201 Created readbody=true>

WebUIでも、Databaseが作られていることが確認できました。

Databases.png

Twitter API KeyとAccess tockenの準備

今回は、twitterのデータを流し込みますので、API KeyとAccess tokenが必要になるため、取得しましょう。
https://apps.twitter.com/
Create New Appボタンから適当なアプリを登録して、遷移後の画面でAPI Keysタブを選ぶと、API KeyとAPI Secretがあります。
画面の下のところに、Your accsess tokenというところがあり、Create my access tokenというボタンがあるので、これで自分用のaccess tokenを生成します。
しばらく(1分ぐらい?)してからrefleshすると、同画面の下のところにAccess tokenとAccess token secretが表示されるので、これを使いましょう。

fluentdでのtwitterデータの流し込み

fluentd本体と、利用するpluginのインストール

$ gem install fluentd fluent-plugin-influxdb fluent-plugin-twitter fluent-plugin-flatten-hash
$ fluentd --setup ./fluent
$ vim fluent/fluent.conf

fluentdの設定は以下のようにします。Twitter API KeyとAccess tokenのところは先ほど取得したもので埋めましょう。

fluent.conf
<source>
  type twitter
  consumer_key        ${YOUR_API_key}
  consumer_secret     ${YOUR_API_Secret}
  oauth_token         ${YOUR_access_token}
  oauth_token_secret  ${YOUR_access_token_secret}
  tag                 twitter.raw.sampling
  timeline            sampling
  output_format       nest
</source>

<match twitter.raw.**>
  type flatten_hash
  tag twitter.sampling
  separator _
</match>

<match twitter.**>
  type influxdb
  host localhost
  port 8086
  dbname qiitademo
  user root
  password root
  time_precision s
  flush_interval 1s
</match>

InfluxDBは、ネストしたデータには対応していないため、そのままでは流し込めません。
fluent-plugin-flatten-hashは、ネストしたhashをいい感じにflatにしてくれるものです。
実はfluent-plugin-twitterのoutput_formatとしてflatという指定も出来るのですが、これだと失敗します。
output_formatでflatを指定しても、値がArrayだったりする項目(entities_hashtagsとか)があると、InfluxDBは受け付けてくれません。
というわけで、InfluxDBに格納する時は、flatten-hashを掛けておけば、とりあえずデータは入ってくれます。

起動して投入してみましょう。

$ fluentd -c fluent/fluent.conf

InfluxDB-CLIで使う

先ほどのDatabase作成はRubyのClient Libraryを使ってみましたが、InfluxDBはHTTP APIがあり、RubyのClient Libraryはそのラッパーです。
(その内、Protobuf APIの実装が予定されているみたいです。)

Node製のCLIがあるので、それも使ってみます。

$ npm install influxdb-cli -g
$ influxdb-cli

基本的なクエリ

  • 接続と件数確認
db> Connecting to http://localhost:8086/db/db ...
db> ✔ ready
db> use qiitademo
db> (empty result)

qiitademo> select count(id) from twitter.sampling
┌───────────────┬────────┐
│ time          │ count  │
├───────────────┼────────┤
│ 1397563652000 │ 403736 │
└───────────────┴────────┘
Query took  1285 ms

データが格納されているようですね。count(*)やcount(1)は使えませんでした。

  • 現在時刻から1分以内、10秒毎の件数取得。
qiitademo> select count(id) from twitter.sampling group by time(10s) where time > now() - 1m
┌───────────────┬───────┐
│ time          │ count │
├───────────────┼───────┤
│ 1397628490000 │ 332   │
│ 1397628480000 │ 344   │
│ 1397628470000 │ 320   │
│ 1397628460000 │ 399   │
│ 1397628450000 │ 402   │
│ 1397628440000 │ 331   │
└───────────────┴───────┘
Query took  12 ms
  • 現在時刻から1分以内の、30秒毎の投稿言語別カウント
qiitademo> select count(id) as cnt from twitter.sampling group by lang,time(30s) where time > now() - 1m and lang in ('ja','en') 
┌───────────────┬─────┬──────┐
│ time          │ cnt │ lang │
├───────────────┼─────┼──────┤
│ 1397628870000 │ 15  │ ja   │
│ 1397628870000 │ 28  │ en   │
│ 1397628840000 │ 324 │ en   │
│ 1397628840000 │ 246 │ ja   │
│ 1397628810000 │ 308 │ en   │
│ 1397628810000 │ 214 │ ja   │
└───────────────┴─────┴──────┘
Query took  16 ms

group byのkeyであるlangはselectしなくても付いてきます。selet lang, count(id) ~ とはしなくて良いです。

  • 集計関数を使って、流れているTweetの発言者フォロワー数に関する30秒毎の統計値を直近3分ぶん取得
qiitademo> select min(user_followers_count) as min_followers, mean(user_followers_count) as mean_followers, percentile(user_followers_count,90) as 90_percentile_followers, median(user_followers_count) as median_followers, max(user_followers_count) as max_follower from twitter.sampling group by time(30s) where time > now() - 3m
┌───────────────┬───────────────┬────────────────────┬─────────────────────────┬──────────────────┬──────────────┐
│ time          │ min_followers │ mean_followers     │ 90_percentile_followers │ median_followers │ max_follower │
├───────────────┼───────────────┼────────────────────┼─────────────────────────┼──────────────────┼──────────────┤
│ 1397629140000 │ 0             │ 2026.4184397163137 │ 2692                    │ 299              │ 57423        │
│ 1397629110000 │ 0             │ 1364.3434247871326 │ 1806                    │ 278              │ 116026       │
│ 1397629080000 │ 0             │ 1835.87394957983   │ 2136                    │ 301              │ 375778       │
│ 1397629050000 │ 0             │ 1693.1923076923097 │ 1834                    │ 292              │ 401730       │
│ 1397629020000 │ 0             │ 1153.275454545456  │ 1979                    │ 311              │ 73554        │
│ 1397628990000 │ 0             │ 1191.8434197886643 │ 1768                    │ 263              │ 116811       │
│ 1397628960000 │ 0             │ 2303.9806243272337 │ 2052                    │ 293              │ 543958       │
└───────────────┴───────────────┴────────────────────┴─────────────────────────┴──────────────────┴──────────────┘
Query took  33 ms

現在(v0.5.4)、利用できる関数はcount,min,max,mean,mode,median,distinct,percentile,histgram,derivative,sum,stddev,first/lastです。
http://influxdb.org/docs/query_language/functions.html

derivativeは、(v_last - v_first) / (t_last - t_first) の値なので、変化率が計算出来ます。
例えば(1次元の)位置を指定すれば速度が、速度的な列を指定すれば加速度のようなものが計算できますね。

histogramは、値をbucketという単位に分割した場合の、各bucketに入る数が返ります。
例えば、フォロワー数のカウントを100,000人単位をbucketとして分布が見たいという時は、以下のようにします。

qiitademo> select histogram(user_followers_count,100000) as hist from twitter.sampling
┌───────────────┬───────────────────┬────────────┐
│ time          │ hist_bucket_start │ hist_count │
├───────────────┼───────────────────┼────────────┤
│ 1397563652000 │ 0                 │ 439461     │
│ 1397563652000 │ 200000            │ 190        │
│ 1397563652000 │ 400000            │ 61         │
│ 1397563652000 │ 800000            │ 9          │
│ 1397563652000 │ 4300000           │ 1          │
│ 1397563652000 │ 2200000           │ 2          │
│ 1397563652000 │ 7100000           │ 1          │
│ 1397563652000 │ 2600000           │ 1          │
│ 1397563652000 │ 3700000           │ 2          │
│ 1397563652000 │ 6200000           │ 2          │
│ 1397563652000 │ 4200000           │ 1          │
│ 1397563652000 │ 1200000           │ 8          │
│ 1397563652000 │ 2900000           │ 2          │
│ 1397563652000 │ 1800000           │ 2          │
│ 1397563652000 │ 1100000           │ 6          │
│ 1397563652000 │ 1900000           │ 2          │
│ 1397563652000 │ 3000000           │ 1          │
│ 1397563652000 │ 4800000           │ 1          │
│ 1397563652000 │ 3400000           │ 14         │
│ 1397563652000 │ 600000            │ 22         │
│ 1397563652000 │ 900000            │ 12         │
│ 1397563652000 │ 1700000           │ 2          │
│ 1397563652000 │ 3200000           │ 1          │
│ 1397563652000 │ 1600000           │ 8          │
│ 1397563652000 │ 2500000           │ 3          │
│ 1397563652000 │ 700000            │ 22         │
│ 1397563652000 │ 1500000           │ 1          │
│ 1397563652000 │ 2100000           │ 2          │
│ 1397563652000 │ 4000000           │ 1          │
│ 1397563652000 │ 1000000           │ 3          │
│ 1397563652000 │ 1300000           │ 1          │
│ 1397563652000 │ 5400000           │ 1          │
│ 1397563652000 │ 2000000           │ 2          │
│ 1397563652000 │ 1400000           │ 5          │
│ 1397563652000 │ 100000            │ 669        │
│ 1397563652000 │ 500000            │ 33         │
│ 1397563652000 │ 300000            │ 83         │
│ 1397563652000 │ 2400000           │ 1          │
│ 1397563652000 │ 3100000           │ 2          │
└───────────────┴───────────────────┴────────────┘
Query took  1369 ms

InfexDBでは、いわゆるRDBのtableにあたるものはseriesという名前で呼ばれます。
クエリの中で、from句のseries名に正規表現が使えます。

  • database中の全てのseriesの中から、macを含む発言の件数カウント。
qiitademo> select count(id) from /.*/ where text=~ /.*mac.*/ and time > now() - 1h
┌───────────────┬───────┐
│ time          │ count │
├───────────────┼───────┤
│ 1397626063000 │ 276   │
└───────────────┴───────┘
Query took  2467 ms

Continuous Queries

トリガ+集計表みたいな感じのものです。
クエリで利用する元のtable/seriesの過去データが削除されても独立しているため、元データの改廃は短期間、集計後の改廃は長期間、という使い方も出来そうです。

selectクエリの最後に"into series名"を付けるだけで設定出来ます。

continuous query登録

  • 登録
qiitademo> select count(id) from twitter.sampling group by time(1m) into twitter.sampling.id.count.1m
  • 登録確認
qiitademo> list continuous queries
┌─────────┬─────────────────┬────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ time    │ sequence_number │ id │ query                                                                                      │
├─────────┼─────────────────┼────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ 1397630 │ 1               │ 1  │ select count(id) from twitter.sampling group by time(1m) into twitter.sampling.id.count.1m │
└─────────┴─────────────────┴────┴────────────────────────────────────────────────────────────────────────────────────────────┘

初回クエリ完了後、twitter.sampling.id.count.1mというseriesが出来ています。その後は自動で更新されます。(過去分の計算を行うのは初回のみ)。

qiitademo> select * from twitter.sampling.id.count.1m where time > now() - 10m
┌───────────────┬─────────────────┬───────┐
│ time          │ sequence_number │ count │
├───────────────┼─────────────────┼───────┤
│ 1397630640000 │ 1               │ 2004  │
│ 1397630580000 │ 1               │ 1953  │
│ 1397630520000 │ 1               │ 2077  │
│ 1397630460000 │ 1               │ 2030  │
│ 1397630400000 │ 1               │ 2068  │
│ 1397630340000 │ 1               │ 2059  │
│ 1397630280000 │ 1               │ 2094  │
│ 1397630220000 │ 1               │ 2118  │
│ 1397630160000 │ 1               │ 1962  │
└───────────────┴─────────────────┴───────┘

GUIでも見てみましょう。

continuous query結果

日本語と英語のtweetについて、follower数の統計値のseriesをcontinuous queryで作ってみます。

$ pry
require 'influxdb'

influxdb = InfluxDB::Client.new 'qiitademo', :username => 'root', :password => 'root'

# lang別のfollower数統計値をtwitter.${lang}_followerというseriesに流し込むContinuous Query
q =<<"EOS"
select
  count(id) as count,
  mean(user_followers_count) as mean_followers,
  percentile(user_followers_count,90) as 90_percentile_followers,
  median(user_followers_count) as median_followers,
  max(user_followers_count) as max_follower
from
  twitter.sampling 
group by
  time(1m)
where
  lang = '${lang}' 
into
  twitter.${lang}_follower.1m
EOS

# Continuous Query登録
['ja','en'].each{|lang| influxdb.query q.gsub('${lang}',lang) }

それぞれ、登録されたことを確認します。

qiitademo> list continuous queries
┌─────────┬─────────────────┬────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ time    │ sequence_number │ id │ query                                                                                      │
├─────────┼─────────────────┼────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ 1397635 │ 1               │ 1  │ select count(id) from twitter.sampling group by time(1m) into twitter.sampling.id.count.1m │
│ 1397635 │ 1               │ 2  │ select                                                                                     │
│         │                 │    │   count(id) as count,                                                                      │
│         │                 │    │   mean(user_followers_count) as mean_followers,                                            │
│         │                 │    │   percentile(user_followers_count,90) as 90_percentile_followers,                          │
│         │                 │    │   median(user_followers_count) as median_followers,                                        │
│         │                 │    │   max(user_followers_count) as max_follower                                                │
│         │                 │    │ from                                                                                       │
│         │                 │    │   twitter.sampling                                                                         │
│         │                 │    │ group by                                                                                   │
│         │                 │    │   time(1m)                                                                                 │
│         │                 │    │ where                                                                                      │
│         │                 │    │   lang = 'ja'                                                                              │
│         │                 │    │ into                                                                                       │
│         │                 │    │   twitter.ja_follower.1m                                                                   │
│         │                 │    │                                                                                            │
│ 1397635 │ 1               │ 3  │ select                                                                                     │
│         │                 │    │   count(id) as count,                                                                      │
│         │                 │    │   mean(user_followers_count) as mean_followers,                                            │
│         │                 │    │   percentile(user_followers_count,90) as 90_percentile_followers,                          │
│         │                 │    │   median(user_followers_count) as median_followers,                                        │
│         │                 │    │   max(user_followers_count) as max_follower                                                │
│         │                 │    │ from                                                                                       │
│         │                 │    │   twitter.sampling                                                                         │
│         │                 │    │ group by                                                                                   │
│         │                 │    │   time(1m)                                                                                 │
│         │                 │    │ where                                                                                      │
│         │                 │    │   lang = 'en'                                                                              │
│         │                 │    │ into                                                                                       │
│         │                 │    │   twitter.en_follower.1m                                                                   │
│         │                 │    │                                                                                            │
└─────────┴─────────────────┴────┴────────────────────────────────────────────────────────────────────────────────────────────┘
Query took  2 ms


qiitademo>  select * from /twitter.*_follower.1m/ where time > now() - 5m
┌───────────────┬─────────────────┬─────────────────────────┬───────┬──────────────┬────────────────────┬──────────────────┐
│ time          │ sequence_number │ 90_percentile_followers │ count │ max_follower │ mean_followers     │ median_followers │
├───────────────┼─────────────────┼─────────────────────────┼───────┼──────────────┼────────────────────┼──────────────────┤
│ 1397635920000 │ 1               │ 3383                    │ 494   │ 1503869      │ 5445.459514170034  │ 364              │
│ 1397635860000 │ 1               │ 2562                    │ 547   │ 177519       │ 1696.5338208409507 │ 339              │
│ 1397635800000 │ 1               │ 2689                    │ 554   │ 112735       │ 1550.3537906137199 │ 328              │
│ 1397635740000 │ 1               │ 3184                    │ 534   │ 403232       │ 3222.5112359550567 │ 386              │
└───────────────┴─────────────────┴─────────────────────────┴───────┴──────────────┴────────────────────┴──────────────────┘
Query took  3 ms
┌───────────────┬─────────────────┬─────────────────────────┬───────┬──────────────┬────────────────────┬──────────────────┐
│ time          │ sequence_number │ 90_percentile_followers │ count │ max_follower │ mean_followers     │ median_followers │
├───────────────┼─────────────────┼─────────────────────────┼───────┼──────────────┼────────────────────┼──────────────────┤
│ 1397635920000 │ 1               │ 1828                    │ 507   │ 40532        │ 877.2899408284014  │ 213              │
│ 1397635860000 │ 1               │ 1861                    │ 526   │ 22805        │ 832.7699619771848  │ 242              │
│ 1397635800000 │ 1               │ 2296                    │ 598   │ 23097        │ 1101.3461538461527 │ 227              │
│ 1397635740000 │ 1               │ 2028                    │ 605   │ 77559        │ 1075.0809917355382 │ 237              │
└───────────────┴─────────────────┴─────────────────────────┴───────┴──────────────┴────────────────────┴──────────────────┘
Query took  3 ms

mergeとjoin

mergeは、それぞれのpoint(レコード)は基本的にそのままで、単純に一つのseriesとしてまとめたものです。
(time,sequence_number,_orig_series)で一意になります。
joinは、同pointである(=timestampとsequence_numberが同一)のものをjoinして、一つのpointとして合わせたものです。

# merge
qiitademo> select * from twitter.ja_follower.1m merge twitter.en_follower.1m limit 4
┌───────────────┬─────────────────┬─────────────────────────┬───────┬──────────────┬────────────────────┬──────────────────┬────────────────────────┐
│ time          │ sequence_number │ 90_percentile_followers │ count │ max_follower │ mean_followers     │ median_followers │ _orig_series           │
├───────────────┼─────────────────┼─────────────────────────┼───────┼──────────────┼────────────────────┼──────────────────┼────────────────────────┤
│ 1397635920000 │ 1               │ 3383                    │ 494   │ 1503869      │ 5445.459514170034  │ 364              │ twitter.en_follower.1m │
│ 1397635920000 │ 1               │ 1828                    │ 507   │ 40532        │ 877.2899408284014  │ 213              │ twitter.ja_follower.1m │
│ 1397635860000 │ 1               │ 2562                    │ 547   │ 177519       │ 1696.5338208409507 │ 339              │ twitter.en_follower.1m │
│ 1397635860000 │ 1               │ 1861                    │ 526   │ 22805        │ 832.7699619771848  │ 242              │ twitter.ja_follower.1m │
└───────────────┴─────────────────┴─────────────────────────┴───────┴──────────────┴────────────────────┴──────────────────┴────────────────────────┘
Query took  15 ms

# join
qiitademo> select * from twitter.ja_follower.1m as ja inner join twitter.en_follower.1m as en limit 4
┌───────────────┬────────────────────────────┬──────────┬─────────────────┬────────────────────┬─────────────────────┬────────────────────────────┬──────────┬─────────────────┬────────────────────┬─────────────────────┐
│ time          │ ja.90_percentile_followers │ ja.count │ ja.max_follower │ ja.mean_followers  │ ja.median_followers │ en.90_percentile_followers │ en.count │ en.max_follower │ en.mean_followers  │ en.median_followers │
├───────────────┼────────────────────────────┼──────────┼─────────────────┼────────────────────┼─────────────────────┼────────────────────────────┼──────────┼─────────────────┼────────────────────┼─────────────────────┤
│ 1397635980000 │ 2090                       │ 552      │ 157989          │ 1181.9818840579715 │ 236                 │ 2475                       │ 452      │ 288973          │ 2367.842920353979  │ 323                 │
│ 1397635920000 │ 1828                       │ 507      │ 40532           │ 877.2899408284014  │ 213                 │ 3383                       │ 494      │ 1503869         │ 5445.459514170034  │ 364                 │
│ 1397635860000 │ 1861                       │ 526      │ 22805           │ 832.7699619771848  │ 242                 │ 2562                       │ 547      │ 177519          │ 1696.5338208409507 │ 339                 │
│ 1397635800000 │ 2296                       │ 598      │ 23097           │ 1101.3461538461527 │ 227                 │ 2689                       │ 554      │ 112735          │ 1550.3537906137199 │ 328                 │
└───────────────┴────────────────────────────┴──────────┴─────────────────┴────────────────────┴─────────────────────┴────────────────────────────┴──────────┴─────────────────┴────────────────────┴─────────────────────┘
Query took  16 ms

尚、公式documentでは、まとめてmergeする例文として

select * from merge /stats.*/

という例が載っていますが、これはInfluxDB v0.5.4においてはsyntax errorとなります。

qiitademo> ✘ Error: Error at 1601400431:1684627267. syntax error, unexpected MERGE, expecting TABLE_NAME or SIMPLE_NAME or REGEX_STRING or INSENSITIVE_REGEX_STRING

また、continuous queryで作ったseriesを使って、更にcontinuous queryを設定しても、動作しませんでした。

qiitademo> select * from twitter.ja_follower.1m as ja inner join twitter.en_follower.1m as en into twitter.follower.lang.1m
qiitademo> select * from twitter.follower.lang.1m limit 10
qiitademo> 

他には、

  • havingが出来ません。
  • 集計関数適用後の演算が出来ません。sum(a+b)はできますが、sum(a)+sum(b)が出来ません。
  • joinすると項目間の計算が出来ません。例えば、
# OK
qiitademo> select ja.count , en.count from twitter.ja_follower.1m as ja inner join twitter.en_follower.1m
┌───────────────┬──────────┬──────────┐
│ time          │ ja.count │ en.count │
├───────────────┼──────────┼──────────┤
│ 1397636460000 │ 511      │ 533      │
│ 1397636400000 │ 509      │ 551      │
│ 1397636340000 │ 536      │ 493      │
│ 1397636280000 │ 548      │ 505      │
└───────────────┴──────────┴──────────┘
Query took  7 ms

# NG
qiitademo> select ja.count + en.count from twitter.ja_follower.1m as ja inner join twitter.en_follower.1m as en limit 4
qiitademo> 

  • custom functionの実装はまだ手付かずのようです。(RedisみたいにLuaで定義できたりすると良いのでは、という提案が出ているだけの段階。)
  • scheduled deleteがまだサポートされていないので、自前で改廃しなきゃいけません。

というあたりが実用としてはまだキビシイところでしょうか。

Grafanaで可視化

インストール

$ git clone git@github.com:torkelo/grafana.git
$ cd grafana/src
$ cp config.sample.js config.js
$ vim config.js
define(['settings'],
    function (Settings) {
      "use strict";

      return new Settings({

        elasticsearch: "http://"+window.location.hostname+":9200",


        datasources: {
          influx: {
            default: true,
                     type: 'influxdb',
                     url: 'http://localhost:8086/db/qiitademo',
                     username: 'root',
                     password: 'root',
          }
        },

        default_route: '/dashboard/file/default.json',
        timezoneOffset: null,
        grafana_index: "grafana-dash",
        panel_names: [ 'text', 'graphite' ]
      });
    });

シンプルに起動

$ python -m SimpleHTTPServer 9000

http://localhost:9000

Grafana-top

グラフ設定

"Graphite test"をクリックしてEditしてグラフを作っていきます。
グラフに使える構文は決まっていて、

select [[func]]([[column]]) from [[series]] where [[timeFilter]] group by time([[interval]]) order asc

となっていて、それぞれの箇所を埋めるだけしか出来ないので、先にcontinuous queryで表示すべき項目は分けて作っておく必要がありますね。
今回は、continuous queryで作った1分単位の集計値のseriesをグラフとして使います。
intervalとcontinuous queryのgroup byで指定した時刻は一致(1分単位)しているため、各intervalにはそれぞれ1件しかpointがありません。
そのため、値をそのまま出して欲しいのですが、functionはmeanでもmedianでも指定しておけばそれで良いです。

言語別流量

言語別フォロワー数

dashbard

DashboardのsaveにはElasticsearchが必要です。

Save Error

雑感

InfluxDBも、Grafanaも、まだまだ発展途上感が強くて、実用としては辛いところがありますが、コンセプトは面白いので、これからの成熟が楽しみです。
リアルタイムな集計処理をするなら、Norikraが、柔軟なクエリが書けたり、UDF/UDAFがあったり、hash/Array型も使えたり、興味深いです。
集計処理のエンジンとしてはNorikraを使いつつ、ダウンサンプリングされたデータ保持にInfluxDB、みたいな使い方もあり得るのかも知れません。

追記

記事中に、joinして項目同士の演算が出来ないとの記載がありますが、v0.5.7 [2014-04-15 release]において、修正されているようです。
https://github.com/influxdb/influxdb/blob/master/CHANGELOG.md