.NETアプリに、ウェブ風の簡易検索やGMailフィルターのようなものを実装してみる

F#とC#で、簡易検索用の動的LINQ生成をやってみました。

こんな風に使います。


//適当なデータ
var data = new[]{
new { Name="yuji1982",Age = 26,Like="F#,Visual Studio", Man=true, Luckyday = new DateTime(2008,1,1) },
new { Name="amachang",Age = 26,Like="JS,javascript,1000sp",Man=true, Luckyday = new DateTime(2008,7,1)},
new { Name="adeton",Age = 20,Like="C#",Man=true, Luckyday = new DateTime(2008,12,1)},
new { Name="zio3",Age = 20,Like="C#,x-box360,XNA Game Studio,Silverlight",Man=true, Luckyday = new DateTime(2008,8,2)},
new { Name="no-0",Age = 126 ,Like="Visual Basic, Expression Studio",Man=false, Luckyday = new DateTime(2008,10,3)},
new { Name="no-1",Age = 0 ,Like="a26a",Man=false, Luckyday = new DateTime(2008,2,1)},
new { Name="no-2",Age = -9,Like="abc",Man=false, Luckyday = new DateTime(2008,3,15)},
new { Name="no-3",Age = 99,Like="Visual Studio",Man=false, Luckyday = new DateTime(2008,12,1)},
new { Name="no-9",Age = 10,Like="C言語",Man=false, Luckyday = new DateTime(2008,4,1)},
new { Name="no-10",Age = 21,Like="javascript",Man=false, Luckyday = new DateTime(2008,4,2)},
new { Name="no-11",Age = 27,Like="C#",Man=true, Luckyday = new DateTime(2008,4,2)},
new { Name="no-12",Age = 23,Like="C",Man=false, Luckyday = new DateTime(2008,4,3)},
};

//クエリ検索の実行
var result = data.Search("(C# or F# or javascript) 20..30 2008/1/1..2008/10/1 Name:-no 1");

//結果を表示してみる。
foreach (var item in result)
{
Console.WriteLine(item);
}


結果
{ Name = yuji1982, Age = 26, Like = F#,Visual Studio, Man = True, Luckyday = 2008/01/01 0:00:00 }
{ Name = amachang, Age = 26, Like = JS,javascript,1000sp, Man = True, Luckyday = 2008/07/01 0:00:00 }

このクエリは以下の内容のand検索になっています。

・どこかにC#かF#かjavascriptが含まれる
・数値が20から30の範囲 (数値型プロパティのどれでも)
・日付が2008/01/01から2008/10/01 (DateTime型プロパティのどれでも)
・Nameにnoが含まれない
・数値が1か文字列に1が含まれる

どうやって動いてるか


検索クエリ

解析(Fsyacc/Fslex)

AST(F#)

Expressionに変換(F#) ← 検索対象指定用のデータ(プロパティ名一覧)

LINQで使用

これをC#でラップして呼べるようにしただけです

何に使えるか?

  • 簡易ツールに使える 

 とりあえずは、簡単なツール(クライアントツール)とかで使えるかなーと思う。
 自分用はてブツールとか、twitterクライアントとか、、パフォーマンスが要求されない部分ならとりあえずあれば便利?

  • Linq to SQLにも使える(たぶん)

 まだ、簡単なパターンのテストしかできてないけど、単純な式ツリーだから、大丈夫だと思う。
 Linq to Object、Linq to SQLの両方に気軽に使えるのが、LinqのExpressionで構築する一番の良さだと思ってる。
 と、言うことで、データベースにも使えるので、webサービスでも使えますね^^

  • GMailフィルターのようなものを簡単に作れる

 文字列に名前を付けて保存するだけで、あの便利なGMailフィルターを真似できますよね^^

 引数が文字列一つで済むから楽>< (この理由はLinq to RESTがリリースされれば関係ないけどw)

クエリに使える演算子について

演算子 説明
AND and & AND(かつ)検索 C# F#
C#とF#含まれる
※スペースを入れてもANDになる
OR or | OR(または)検索 C# or F#
C#かF#が含まれる
()
(括弧)
グループ化 (C# or F#) (2005 or 2008)
Not not ! 否定 !C#
C#が含まれない
-
(ハイフン)
除外 -C#
C#が含まれない
※基本は否定と同じ、違いはグループ化した時の動作
-(a b)は!(a or b)と同じ
数値の前に使うとマイナスとして判断されるので-(9)などにする必要がある
ターゲット名: 検索対象のプロパティを指定する
ターゲット名はプロパティ名の別名として設定できる
ターゲットを指定しないものはAllとして設定したプロパティ全てが対象になる。
名前:yuji
Nameプロパティにyujiが含まれる
""
(引用符)
フレーズ検索 "Visual Studio"
"x-box"
とかに使う。
また、数値9を文字"9"にするなど
{}
(中括弧)
ORでグループ化する {C# F#}
(C# or F#)と同じ
.. 範囲指定 20..30
20から30
※数値か日付にのみに使える。
< > <= >= 関係演算子(って言うのかな^^;) <20
20未満
is:ターゲット名 bool演算 is:Man
Manプロパティがtrueかどうか

数値と日付の扱いについて

  • 数値と文字の違い

 数値9で検索すると、9が含まれる文字列と数値9にヒットする。
 文字"9"で検索すると、9が含まれる文字列と9が含まれる数値(19,-90とか)にヒットする。

  • 日付のフォーマット

 yyyy/MM/ddとyy/MM/ddを想定してる(Fslexの正規表現がうまくいってないので、適当ですが・・・)
 yy/MMやMM/ddって対応したいけど、どうやろうかなー

課題

おわり

F#の練習のつもりでやってたから、コードがぐちゃぐちゃ^^;コメントになってるところがありすぎるw
ソースはあとでうpします。とりあえず、dll上げときますので、試してみる方はどうぞ^^

(追記)ソース晒しておきます。

ソースダウンロード(DynamicSearch.zip)
DLLダウンロード(DynamicSearchDLL.zip)

※.NET Fx3.5とF#が必要です。

F#のダウンロードは以下のページから。ライセンスもこのページから見てください。
http://research.microsoft.com/fsharp/release.aspx

F#のDLLが数個あればいいので、zip版からサクっと使うだけでいいんだけど、
非商用なら、一緒に配っちゃってもいいのかなー・・・(必死で読んでもよくわからん^^;