.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 Object、Linq to SQLの両方に気軽に使えるのが、LinqのExpressionで構築する一番の良さだと思ってる。
と、言うことで、データベースにも使えるので、webサービスでも使えますね^^
- GMailフィルターのようなものを簡単に作れる
文字列に名前を付けて保存するだけで、あの便利なGMailフィルターを真似できますよね^^
- WebService(Soap,REST)を作るのが楽^^
引数が文字列一つで済むから楽>< (この理由は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って対応したいけど、どうやろうかなー
課題
- エラー処理とかまだ全くできてない。
- システム変数のようなものを実装したら便利かなーとか(@NowDateみたいな)
ちょっとコードがひどいすぎるからリストラクチャリングするムリ^^;諦め- Google Bookmarksとはてブの差分を出してみる。その1 - yuji1982の日記の続きで利用する。(フィルターとか作ってみる)
おわり
F#の練習のつもりでやってたから、コードがぐちゃぐちゃ^^;コメントになってるところがありすぎるw
ソースはあとでうpします。とりあえず、dll上げときますので、試してみる方はどうぞ^^
(追記)ソース晒しておきます。
ソースダウンロード(DynamicSearch.zip)
DLLダウンロード(DynamicSearchDLL.zip)
※.NET Fx3.5とF#が必要です。
F#のダウンロードは以下のページから。ライセンスもこのページから見てください。
http://research.microsoft.com/fsharp/release.aspx
F#のDLLが数個あればいいので、zip版からサクっと使うだけでいいんだけど、
非商用なら、一緒に配っちゃってもいいのかなー・・・(必死で読んでもよくわからん^^;