Rustで簡単ElasticsearchClient

皆さんこんばんは。私にとって一日の境界は午前9時なので、まだ19日目のはずです。
はい。すみません。遅くなりましたが、これはRust Adventcalendarの19日目です。

Rustは完全に趣味でやっている初心者なのですが、せっかく触っているなら
仕事でも使いたくなりますよね。
私はElasticsearchを仕事でよく触るので、今回はRustのElasticsearchClientを
紹介していきます。

今回使うライブラリは
elastic-rs
です。

まずはクライアントオブジェクトを作ります。この辺は大体同じですね。

   let client = SyncClientBuilder::new().build()?;

検索をしたいときには、elasticsearchのqueryをそのまま使えます。

   let res = client
      .search::<Value>()
      .index("_all")
      .body(json!({
          "query": {
              "query_string": {
                  "query": "*"
              }
          }
      }))
      .send()?;

また、documentを登録したいときは、structを定義してMapping・投入ができます。

  struct docType {
      id: i32,
      title: String,
      timestamp: Date<DefaultDateMapping>,
  };
  let document = docType {
      id: 1,
      title: String::from("adventcalendar"),
      timestamp: Date::now(),
  };
  client.document_put_mapping::<docType>(Index::from("sample")).send()?;
  client.document_index(sample_index(), id(doc.id), doc).send()?;

こんな感じで使えます。
まだver0.20.8なのですが、やりたいことは大体できます。すごい便利です。
これを使えばちょっとしたElasticsearchClient作れますね。

それでは、今回はこの辺で。

Apache Arrowとparquetを使ってみる

これはPython Advent Calnedarの3日目です。
皆さんこんにちは。個人ブログを更新するのはとても久しぶりですが、
たまには真面目に書こうと思います。

  今回は、Apache Arrowというものを小耳にはさんだので、
どんなものなのか試してみたいと思います。

そもそもApache Arrowとは

 ざっくり言ってしまえばデータフォーマットの仕様です。
データを効率的に、インメモリで管理することを目的として
作られた仕様だそうです
詳しくはこのスライドがわかりやすいです。
スケールアウト・インメモリ分析の標準フォーマットを目指す Apache Arrow と Value Vectors - Tokyo Apa…

 いろいろ検証

 とりあえずいろいろ動かして検証してみました。
環境は、GCPのCompute Engineを使いました。

CPU: 4コア
メモリ: 16GB
Python: 3.5.1
pyarrot: 0.7.1

  まずはファイルから読み込んでメモリ上のサイズがどうなるのかを見てみます。
今回はデータセットとして
Uber Pickups in New York City | Kaggle Uber Pickups in New York City | Kaggle

を使います。

もとのCSVファイルのサイズは、約26110KBでした。

まずは、pandasのDataFrameとして読み込むとどうでしょうか。

import pandas as pd
import pyarrow as pa

df = pd.read_csv("uber-raw-data-apr14.csv")

 

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 564516 entries, 0 to 564515
Data columns (total 4 columns):
Date/Time    564516 non-null object
Lat          564516 non-null float64
Lon          564516 non-null float64
Base         564516 non-null object
dtypes: float64(2), object(2)
memory usage: 17.2+ MB

およそ17.2MB使用しているということがわかりました。
続いて、arrowのTableに変換するとどうなるでしょうか。
pyarrow::total_allocated_bytes()というメソッドを使って調べてみます

pa.total_allocated_bytes()
0
table = pa.Table.from_pandas(df)
pa.total_allocated_bytes()
30286208  

あれ、30MBとpandasのデータフレームより大きいですね。
正直この方法が正しいのかも確信はないので、まだ調査が必要ですね。

次は、ファイルとのやり取りについて見てみましょう。 どうやら、ArrowはParquetに効率よくやり取りできる形式のようなので、
csv <-> DataFrameとparquet <-> arrowで見比べてみます。

%timeit df.to_csv("test.csv")
2.14 s ± 37.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit  df2 = pd.read_csv("uber-raw-data-apr14.csv")
364 ms ± 2.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit pq.write_table(table, "uber-raw-data-apr14.pq")
139 ms ± 2.92 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit table2 = pq.read_table("uber-raw-data-apr14.pq")
73.4 ms ± 801 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

CSVの読み書きより断然早いことがわかりますね。
これは今後大規模なデータを扱うときに、便利そうです。

まとめ

今回はApache Arrowをpythonからとりあえず使ってみるということをしました。
今後は、pysparkとの連携というのもspark2.3からできるようになるらしいので、
試してみたいですね。