Windows Search 4.0をC#から利用する Part2

次にAdvanced Query Syntax(AQS)を使う方法について。Part1はこっち。

AQSはWindows Search用(たぶん)の検索条件指定で使う構文で、たとえば「パンダ 白浜」と入れて両方のキーワードで検索するとか、ファイルの作成日で検索するとかできるやつです。インストールしたWindows Searchのヘルプの、検索条件の項目に詳しく説明があります。

で、Windows Searchのインデックス情報は、OLE DB経由でしかアクセスできないようなので、AQSをWindows SearchのOLE DBプロバイダ向けのSQL構文に変換して検索する必要があります。それは自力でやるんではなくて、ISearchQueryHelper Interfaceというものが既に用意されています。
http://msdn.microsoft.com/en-us/library/aa965451(VS.85).aspx

SDKの中に、C++C#の両方でISearchQueryHelperを使用したサンプルコードがありました。これはWindows Search 3.x向けみたいですが、4でも使えます。
http://msdn.microsoft.com/en-us/library/bb286798(VS.85).aspx
Microsoft Windows Search 3.x SDK
http://www.microsoft.com/downloads/details.aspx?FamilyID=645300AE-5E7A-4CE7-95F0-49793F8F76E8&displaylang=en


こんな感じのコード↓
(いろいろ端折ってるのでこのままでは動きません。詳細はSDKの中のサンプルプロジェクトDSearchとかを見てください)

private void Search()
{
    // Thie uses SearchAPI interop assembly
    CSearchManager manager = new CSearchManager();
    CSearchCatalogManager catalogManager = manager.GetCatalog("SystemIndex");
    CSearchQueryHelper queryHelper = catalogManager.GetQueryHelper();
    queryHelper.QuerySelectColumns = @"
		System.Search.Rank,
		System.ItemFolderPathDisplay,
		System.ItemPathDisplay ,
		System.ItemFolderNameDisplay ,
		System.ItemName ,
		System.FileExtension ,
		System.FileName ,
		System.ItemTypeText ,
		System.ItemDate ,
		System.DateAccessed ,
		System.ItemAuthors,
		System.Size
		";

    // Generate SQL from our parameters, converting the userQuery from AQS->WHERE clause
    string sqlQuery = queryHelper.GenerateSQLFromUserQuery("パンダ 白浜");

    // --- Perform the query ---
    // create an OleDbConnection object which connects to the indexer provider with the windows application
    using (System.Data.OleDb.OleDbConnection conn = new OleDbConnection(queryHelper.ConnectionString))
    {
        // open it
        conn.Open();

        OleDbCommand command = new OleDbCommand(sqlQuery, conn);
        OleDbDataReader WDSResults = command.ExecuteReader();
        
        int nReads = 0;
        int nResults = 0;
        while (WDSResults.Read())
        {
            nResults++;

            if (offsetRows <= nResults && (nReads < maxRows || maxRows == 0))
            {
                nReads++;

                DataRow dr = ds.Tables[0].NewRow();

                for (int i = 0; i < WDSResults.VisibleFieldCount; i++)
                {
                    dr[i] = WDSResults.GetValue(i);
                }

                ds.Tables[0].Rows.Add(dr);
            }
            else if (maxRows <= nReads)
            {
                //最大読み込み件数を超えたため終了
                break;
            }                    
        }
        WDSResults.Close();
        conn.Close();
    }
}



/// <summary>
/// 検索結果のDataSetを作成
/// </summary>
/// <returns></returns>
DataSet GetDataSet()
{
    DataSet ds = new DataSet("DSearch");
    ds.Tables.Add(new DataTable("Results"));

    ds.Tables[0].Columns.Add(new DataColumn("Rank", typeof(Int32)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemFolderPathDisplay", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemPathDisplay", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemFolderNameDisplay", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemName", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("FileExtension", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("FileName", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemTypeText", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemDate", typeof(DateTime)));
    ds.Tables[0].Columns.Add(new DataColumn("DateAccessed", typeof(DateTime)));
    ds.Tables[0].Columns.Add(new DataColumn("ItemAuthors", typeof(string)));
    ds.Tables[0].Columns.Add(new DataColumn("Size", typeof(Int32)));
    return ds;
}


ちなみに、常にTOP句を指定しない限り、OleDbDataReaderではなくてDataAdapterを使うのは避けたほうがいいです。検索結果件数が数万件を超えたあたりから、結果の取得に10分以上かかったりします。

続く。。。Part3