特集:Road to LINQ C#で解説する「データ処理の直交化と汎用化」 岩永 信之2011/06/14 |
|
|
■ LINQ to ……
これまでの説明では、データの取得元をIEnumerable<T>インターフェイスに限っていた。IEnumerable<T>インターフェイスを使うと、データの扱い方に以下のような制約がかかってしまう。
- pull型: プログラムがデータを能動的に取り出す。
- 内部実行: データはプログラム内で加工する。
そして、データの取得方法としては、この逆も考えられるのである。
- push型: 外部から送られてくるデータを受動的に受け取る。
- 外部クエリ: データの加工を外部システムに行ってもらう。
.NET Frameworkには、push型データ取得用のIObservable<T>インターフェイス(System名前空間)と外部クエリ用のIQueryable<T>インターフェイス(System.Linq名前空間)が用意されている。
ここで、今回のテーマ的に気になる点は、Figure 11に示すようなが必要なのか、Figure 12に示すようなだけでデータ処理できるのかである。
Figure 11 通りの実装 |
同じデータ処理を行いたくても、それぞれ別の実装が必要なのか。 |
Figure 12 通りの実装 |
異なるインターフェイスでも同じ実装でデータ処理が行えるのか。 |
LINQはFigure 12のを実現する。といっても、インターフェイスが異なるため、完全にコードを共通化できるわけではないのだが、同じような書き方ができる。少なくとも、学習コストは大幅に下がるだろう。
● push型データ取得
push型データ取得の典型例は、携帯電話のキャリア・メールである。携帯電話側から能動的にメールを取りにいっているのではなく、サーバから送られてくるメールを受動的に受け取るのだ。
また、最近の電子機器は、GPS(Global Positioning System: 全地球測位システム)など、さまざまなセンサを搭載している。通常、センサAPIでは、プログラムが能動的にセンサの状態を調べるのではなく、受動的にセンサからデータを受け取ることになる。
このようなpush型データ取得(=受動的な待ち受け)は、携帯型機器において特に重要になるだろう。能動的な動作は電力消費が激しく、バッテリ駆動の携帯型機器には不向きなのである*2。
push型のデータ、すなわち、IObservable<T>インターフェイスに対するLINQを提供するのが「Reactive Extensions(通称、Rx)」*3というライブラリだ。上記のサンプルでは、説明も兼ねてRx相当の機能の一部を「再発明」しているのだが、ここではRxを使った例をList 13に示す。説明を簡単化するためにタイマーでデータをpushしているが、この部分はサーバからの通知だったり、センサ入力だったりに適宜読み替えてほしい(ちなみに、ObservableはSystem.Reactive.Linq名前空間のクラスである)。
*2 そのため、Windows Phone 7には、「Push Notification(プッシュ通知)」というサーバからデータを送りつける仕組みが用意されていたり、Reactive Extensions(通称、Rx)が標準搭載されていたりする。 |
*3 長らく研究的位置付けのプロジェクトだったが、2011年4月に「製品レベル」として正式リリースされた。 |
|
|
List 13 push型で取得したデータに対するLINQ |
● 外部クエリ
「外部システムに記憶されたデータを取得してきて処理を行う」という場面は非常に多い。RDBMS(Relational Database Management System)からのデータ取得が典型的な例だろう。
Figure 13に示すように、IEnumerable<T>インターフェイスを使っても外部システムからのデータ取得はできなくはないのだが、データを全件返すという部分がネックになる。外部システムとの接続はネットワークを介することが多く、通信量の増大が性能の劣化に直結する。
一方、IQueryable<T>インターフェイスを使う場合、加工依頼(これを「クエリ(query)」と呼ぶ)を送り、外部システム上でデータ加工まで行ってもらい結果だけを受け取る。クリエの典型例は、RDBMSに対するSQL文だ。
Figure 13 外部システムからのデータ取得 |
IEnumerable<T>インターフェイスを使う場合とIQueryable<T>インターフェイスを使う場合での差異。加工まで外部システムに任せるかどうかの差がある。 |
LINQでも、LINQ to SQLやLINQ to Entitiesなど、いわゆるO/Rマッパーが有名なので、「外部システム」の部分にRDBMSを思い浮かべがちだろう。もちろん、代表例ではある。
List 14にLINQ to Entitiesの利用例を示そう。
|
|
List 14 LINQ to Entitiesの利用例 | |
SampleDataContextクラスのParentsプロパティの型はIQueryable<T>インターフェイスである。 |
しかし、O/RマッパーだけがLINQではない。例えば、最近では、REST(Representational State Transfer)形式でのHTTPを介したデータ取得を行えるシステムが増えている。この場合にも同様の通信量問題があり、その回避策としてデータ加工の条件を渡して加工結果だけを返してもらう場合が多い。
また、Hadoopのような分散データ処理も、この「外部システムへのクエリ」の一種と見なせるだろう。IQueryable<T>インターフェイスを使って実現できる。
LINQと関連して、以下のような製品もある。
- OData: REST形式でデータ取得を行うためのプロトコル。ODataサービスは、Visual Studioから「サービス参照」することで、IQueryable<T>インターフェイスを介したデータ取得が行える。
- Windows HPC Server: マイクロソフト製の分散データ処理環境。LINQを使ってWindows HPC Server上の分散データ処理を行うための「LINQ to HPC」というライブラリも提供されている。
■ クエリ式
よく、「LINQに慣れてくると、foreachなどのループを書く量が減る」といわれる。なぜかというと、LINQはループ相当の機能を持っているからである。List 8のforeach文が、List 12のSelect/Whereメソッドに置き換わるわけである。元のループと比べての利点は以下のとおりだ。
- 処理を“軸”で直行分解できる
- パイプライン型の書き方になる
- push型データ処理や外部クエリにも応用が利く
しかし、1つ問題もある。2重ループに相当するコードを書くのが難しい。例えば、List 15のようなデータ処理を考えてみよう。
|
|
List 15 2重ループでデータ処理する例 |
このような、2重ループに相当するLINQクエリにはSelectManyメソッドを使う。List 16のように書けばよい。
|
|
List 16 SelectManyメソッドを使って2重ループ相当のLINQクエリを書く例 |
しかし、この書き方には少々慣れが必要で、すぐに書ける人は少ないらしい。「らしい」と書いたが、実際、C# 3.0をリリースするに当たってユーザビリティ・テストを行ったところ、「書ける人がほとんどいない」という結果が得られたといわれている。
たまに「関数型脳が必要」などと例えられることもあるように、SelectManyのような書き方も関数型言語では一般的なのだが、C#ではやはり、List 15の2重ループからの類推が求められるようだ。
そこで導入されたのがクエリ式(query expression)である。List 17に示すような、「SQL風の式」だ。
|
|
List 17 クエリ式を使って2重ループ相当のLINQクエリを書く例 | |
2つ目のfrom句はSelectManyメソッドに展開される。 |
foreach文のところをfrom句に、if文のところをwhere句に、「yield return」を書くべきところをselect句に置き換えればよい。これで、List 16のようなメソッド呼び出しに変換される。
クエリ式はいわば、命令型言語と関数型言語の橋渡しといっていいだろう。
INDEX | ||
特集:Road to LINQ | ||
C#で解説する「データ処理の直交化と汎用化」 | ||
1.直交性 | ||
2.LINQ to Objectに至るまで | ||
3.LINQ to ……/クエリ式 | ||
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|
- - PR -