Hatena::ブログ(Diary)

ザリガニが見ていた...。 このページをアンテナに追加 RSSフィード

2008-12-01

スティッキーズのSpotlight対応ヘルパー(全文検索可能バージョン)

前回の日記で作ってみたスティッキーズをSpotlightに対応させるプラグインとヘルパーを使っているうちに、ちゃんと検索できる単語と、出来ない単語があることに気付いた。というより、ちゃんと検索できない単語の方が多いと思う...。

試しに、スティッキーズの内容を「テキストに書き出す...」してみると、書き出したテキストファイルについては今までスティッキーズがSpotlightの検索にヒットしない不満が嘘のように、気持ち良くヒットした。

この現状では、とてもSpotlight対応のスティッキーズとは言えない...。何とかしなければ...。

テキストファイルとスティッキーズデータファイルをSpotlightが認識する時の違い

  • ターミナルで以下のコマンドで検索対象ファイルを調べると、Spotlightがどのように認識しているかが表示された。
$ mdimport -d2 検索対象ファイルパス
  • スティッキーズを初めて起動したときのデフォルトの状態を確認してみた。
  • 「メモにしましょう!」のメモウィンドウだけ、テキストファイルとして書き出しておいた。

f:id:zariganitosh:20081201142408p:image

f:id:zariganitosh:20081201142421p:image


テキストファイルの場合
  • メモの内容は、一般的なテキストを表現するkMDItemTextContent属性に、文字列として認識されているようだ。
MacBook:~ Guest$ mdimport -d2 /Users/Guest/Documents/メモにしましょう!.rtf 
(Info) Import: Import '/Users/Guest/Documents/メモにしましょう!.rtf' type 'public.rtf' using '/System/Library/Spotlight/RichText.mdimporter'
2008-12-01 14:05:17.540 mdimport[2559:10b] Imported '/Users/Guest/Documents/メモにしましょう!.rtf' of type 'public.rtf' with plugIn /System/Library/Spotlight/RichText.mdimporter.
2008-12-01 14:05:17.543 mdimport[2559:10b] Attributes: {
    "_kMDItemFinderLabel" = <null>;
    "com_apple_metadata_modtime" = 249800612;
    kMDItemAuthors = <null>;
    kMDItemComment = <null>;
    kMDItemContentCreationDate = 2008-12-01 14:03:32 +0900;
    kMDItemContentModificationDate = 2008-12-01 14:03:32 +0900;
    kMDItemContentType = "public.rtf";
    kMDItemContentTypeTree =     (
        "public.rtf",
        "public.text",
        "public.data",
        "public.item",
        "public.content"
    );
    kMDItemCopyright = <null>;
    kMDItemCreator = <null>;
    kMDItemDisplayName =     {
        "" = "\U30e1\U30e2\U306b\U3057\U307e\U3057\U3087\U3046\Uff01.rtf";
    };
    kMDItemEditors = <null>;
    kMDItemKeywords = <null>;
    kMDItemKind =     {
        "" = NSRTFPboardType;
        en = "Rich Text Format (RTF)";
        ja = "\U30ea\U30c3\U30c1\U30c6\U30ad\U30b9\U30c8\U30d5\U30a9\U30fc\U30de\U30c3\U30c8\Uff08RTF\Uff09";
    };
    kMDItemOrganizations = <null>;
    kMDItemSubject = <null>;
    kMDItemTextContent = "\U30e1\U30e2\U306b\U3057\U307e\U3057\U3087\U3046\Uff01\n\n\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U3092\U4f7f\U3046\U3068\U3001\U3053\U306e\U30b5\U30f3\U30d7\U30eb\U306e\U3088\U3046\U306b\U6587\U7ae0\U3092\U30e1\U30e2\U3068\U3057\U3066\U30c7\U30b9\U30af\U30c8\U30c3\U30d7\U306b\U8868\U793a\U3067\U304d\U307e\U3059\U3002 \U3061\U3087\U3063\U3068\U3057\U305f\U899a\U3048\U66f8\U304d\U306a\U3069\U3092\U66f8\U304d\U7559\U3081\U308b\U5834\U6240\U3068\U3057\U3066\U3001\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U30e1\U30e2\U3092\U4f7f\U7528\U3057\U3066\U304f\U3060\U3055\U3044\U3002\U307e\U305f\U3001\U30e1\U30e2\U306f\U3088\U304f\U4f7f\U3046\U6587\U7ae0\U3084\U753b\U50cf\U3092\U53ce\U3081\U3066\U304a\U304f\U5834\U6240\U3068\U3057\U3066\U3082\U4f7f\U7528\U3067\U304d\U307e\U3059\U3002\n\n\U2022 \U30e1\U30e2\U3092\U9589\U3058\U308b\U306b\U306f\U3001\U30af\U30ed\U30fc\U30ba\U30dc\U30bf\U30f3\U3092\U30af\U30ea\U30c3\U30af\U3057\U3057\U307e\U3059\U3002\n\n\U2022 \U30e1\U30e2\U3092\U5c0f\U3055\U304f\U3059\U308b\U306b\U306f\U3001\U30bf\U30a4\U30c8\U30eb\U30d0\U30fc\U3092\U30c0\U30d6\U30eb\U30af\U30ea\U30c3\U30af\U3057\U307e\U3059\U3002\n\n\U8868\U793a\U4e2d\U306e\U30e1\U30e2\U306f\U3001\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U3092\U8d77\U52d5\U3059\U308c\U3070\U3044\U3064\U3067\U3082\U73fe\U308c\U307e\U3059\U3002\n";
    kMDItemTitle = <null>;
}
スティッキーズデータファイルの場合
  • メモの内容は、独自に定義した"com_apple_stickies_aaa_noteTitle"属性に、文字列の配列として認識されているようだ。
    • kMDItemTextContent = ("(おそらく)UTF-8の文字コード", "(おそらく)UTF-8の文字コード")
MacBook:~ Guest$ mdimport -d2 /Users/Guest/Documents/StickiesData.aaa 
(Info) Import: Import '/Users/Guest/Documents/StickiesData.aaa' type 'com.apple.stickies.aaa' using '/Library/Spotlight/StickiesImporter.mdimporter'
2008-12-01 14:00:11.809 mdimport[2519:10b] Imported '/Users/Guest/Documents/StickiesData.aaa' of type 'com.apple.stickies.aaa' with plugIn /Library/Spotlight/StickiesImporter.mdimporter.
2008-12-01 14:00:11.811 mdimport[2519:10b] Attributes: {
    "_kMDItemFinderLabel" = <null>;
    "com_apple_metadata_modtime" = 249800400;
    "com_apple_stickies_aaa_noteTitle" =     (
        "\U30e1\U30e2\U306e\U30ab\U30b9\U30bf\U30de\U30a4\U30ba\U306f\U7c21\U5358\U3067\U3059\U3002\n\n\U4f5c\U6210\U3057\U305f\U30e1\U30e2\U66f8\U304d\U3092\U76ee\U7acb\U305f\U305b\U3066\U3001\U3059\U3050\U5206\U304b\U308b\U3088\U3046\U306b\U3057\U307e\U3057\U3087\U3046\U3002\n\n\U2022 \U30d5\U30a9\U30f3\U30c8\Uff08fonts\Uff09\U3084\U30d5\U30a9\U30f3\U30c8\U30b5\U30a4\U30ba\U3092\U6307\U5b9a\U3067\U304d\U307e\U3059\U3002\n\U2022 \U30dc\U30fc\U30eb\U30c9\Uff08bold\Uff09\U3084\U30a4\U30bf\U30ea\U30c3\U30af\Uff08italic\Uff09\U306a\U3069\U306e\U30b9\U30bf\U30a4\U30eb\U3084\U30ab\U30e9\U30fc\U3092\U6307\U5b9a\U3067\U304d\U307e\U3059\U3002\n\U2022 \U753b\U50cf\U306e\U8cbc\U308a\U4ed8\U3051\U304c\U3067\U304d\U307e\U3059\U3002 \Ufffc \n\n\U3053\U306e\U4ed6\U306b\U3082\U3001\U30b9\U30da\U30eb\U30c1\U30a7\U30c3\U30af\U3001\U30e1\U30e2\U306e\U8aad\U307f\U8fbc\U307f\U30fb\U66f8\U304d\U51fa\U3057\U306a\U3069\U3001\U30e1\U30e2\U3092\U7de8\U96c6\U3059\U308b\U305f\U3081\U306e\U6a5f\U80fd\U304c\U305f\U304f\U3055\U3093\U3042\U308a\U307e\U3059\U3002\U307e\U305f\U3001\U591a\U304f\U306e\U30a2\U30d7\U30ea\U30b1\U30fc\U30b7\U30e7\U30f3\U3067\U306f\U300c\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30e1\U30e2\U3092\U4f5c\U6210\U300d\U30b5\U30fc\U30d3\U30b9\U3092\U5229\U7528\U3067\U304d\U307e\U3059\U3002\n\n\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U306e\U8a73\U7d30\U306b\U3064\U3044\U3066\U306f\U3001\U30d8\U30eb\U30d7\U3092\U53c2\U7167\U3057\U3066\U304f\U3060\U3055\U3044\U3002",
        "\U30e1\U30e2\U306b\U3057\U307e\U3057\U3087\U3046\Uff01\n\n\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U3092\U4f7f\U3046\U3068\U3001\U3053\U306e\U30b5\U30f3\U30d7\U30eb\U306e\U3088\U3046\U306b\U6587\U7ae0\U3092\U30e1\U30e2\U3068\U3057\U3066\U30c7\U30b9\U30af\U30c8\U30c3\U30d7\U306b\U8868\U793a\U3067\U304d\U307e\U3059\U3002 \U3061\U3087\U3063\U3068\U3057\U305f\U899a\U3048\U66f8\U304d\U306a\U3069\U3092\U66f8\U304d\U7559\U3081\U308b\U5834\U6240\U3068\U3057\U3066\U3001\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U30e1\U30e2\U3092\U4f7f\U7528\U3057\U3066\U304f\U3060\U3055\U3044\U3002\U307e\U305f\U3001\U30e1\U30e2\U306f\U3088\U304f\U4f7f\U3046\U6587\U7ae0\U3084\U753b\U50cf\U3092\U53ce\U3081\U3066\U304a\U304f\U5834\U6240\U3068\U3057\U3066\U3082\U4f7f\U7528\U3067\U304d\U307e\U3059\U3002\n\n\U2022 \U30e1\U30e2\U3092\U9589\U3058\U308b\U306b\U306f\U3001\U30af\U30ed\U30fc\U30ba\U30dc\U30bf\U30f3\U3092\U30af\U30ea\U30c3\U30af\U3057\U3057\U307e\U3059\U3002\n\n\U2022 \U30e1\U30e2\U3092\U5c0f\U3055\U304f\U3059\U308b\U306b\U306f\U3001\U30bf\U30a4\U30c8\U30eb\U30d0\U30fc\U3092\U30c0\U30d6\U30eb\U30af\U30ea\U30c3\U30af\U3057\U307e\U3059\U3002\n\n\U8868\U793a\U4e2d\U306e\U30e1\U30e2\U306f\U3001\U30b9\U30c6\U30a3\U30c3\U30ad\U30fc\U30ba\U3092\U8d77\U52d5\U3059\U308c\U3070\U3044\U3064\U3067\U3082\U73fe\U308c\U307e\U3059\U3002\n"
    );
    kMDItemContentCreationDate = 2008-12-01 13:53:00 +0900;
    kMDItemContentModificationDate = 2008-12-01 14:00:00 +0900;
    kMDItemContentType = "com.apple.stickies.aaa";
    kMDItemContentTypeTree =     (
        "com.apple.stickies.aaa",
        "public.data",
        "public.item",
        "public.composite-content",
        "public.content"
    );
    kMDItemDisplayName =     {
        "" = "StickiesData.aaa";
    };
    kMDItemKind =     {
        "" = "The StickiesDatabase Format";
    };
}

現状分析

上記の結果から...

  • 一般的なテキストを表現するkMDItemTextContent属性であれば、あらゆる単語区切りで全文検索が可能になっている。
  • ところが、独自に定義した"com_apple_stickies_aaa_noteTitle"属性だと、何らかの条件によって検索できない単語がかなりの確率で存在する。(かなり大問題)
  • Spotlightの認識としては「kMDItemTextContent属性のテキストデータ」か「"com_apple_stickies_aaa_noteTitle"属性のテキストデータの配列」かの違いがある。
  • メモの内容としては、(配列かどうかの違いはあるが)全く同じテキストデータを認識しているので、同じレベルで全文検索が可能になって欲しいものだ。

妄想

スティッキーズデータも「kMDItemTextContent属性のテキストデータ」としてSpotlightに渡せば、満足できる全文検索のレベルになるんじゃないだろうか?

  • で、Spotlightプラグインの仕組みとか全くちゃんと理解できていないのだけど、GetMetadataForFile.mがSpotlightに検索データを渡す役割を担っているようだ。
  • GetMetadataForFile.mの中で、以下メッセージ書式で呼び出すことで、Spotlightは検索データを認識してくれるみたい。
[(NSMutableDictionary *)attributes setObject:検索データオブジェクト forKey:属性を表現する文字列];

現状は、検索データオブジェクトに文字列の配列を指定しているが、その配列の中身をすべて結合して一つの文字列にしてしまえば良いんじゃないかと。

  • 配列としてSpotlightに渡していても、検索結果からメモのウィンドウを特定する情報を渡せている訳でもなく、とにかく検索ワードがヒットするかどうかが重要なので、一つの文字列に結合してしまっても問題ないはず。
  • もっと言えばおそらく、独自のSpotlight属性を定義するチュートリアルとして、敢えてわざわざ独自定義の属性"com_apple_stickies_aaa_noteTitle"を設定していると考えられる。本来は一般的なテキスト属性で何ら問題ない検索が出来るのではないか...。

GetMetadataForFile.mの修正

  • 妄想を実装するため、以下のように修正してみた。(3箇所)
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h> 
#include <Foundation/Foundation.h>

#import "Document.h"
...(コメント中略)...
Boolean GetMetadataForFile(
                           void* thisInterface, 
                           CFMutableDictionaryRef attributes, 
                           CFStringRef contentTypeUTI,
                           CFStringRef pathToFile)
{
    Boolean success=NO;
    NSAutoreleasePool *pool;
	
    // Don't assume that there is an autorelease pool 
    //around the calling of this function.
    pool = [[NSAutoreleasePool alloc] init];
	
    /* Pull any available metadata from the file */
	
    //The Document class provides the methods necessary to 
    //manipulate the StickiesDatabase file
    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:
        [NSUnarchiver unarchiveObjectWithFile:
            (NSString*)pathToFile]];
	
    [array autorelease];
	
    NSEnumerator *enumerator = [array objectEnumerator];
    Document *d;
//1/NSMutableArray* tempArray = [NSMutableArray array];
    NSMutableString* tempString = [NSMutableString string];
	
    while (d = [enumerator nextObject]) { 
        NSString *t = [d stringValue];
//2/    [tempArray addObject:t];
        [tempString appendString:t];
    }
	
//3/[(NSMutableDictionary *)attributes setObject:tempArray
//3/                                      forKey:@"com_apple_stickies_aaa_noteTitle"];
    [(NSMutableDictionary *)attributes setObject:tempString
                                          forKey:(NSString *)kMDItemTextContent];
	
    // return YES so that the attributes are imported and
    // add more resilient error handling at your own discretion
    success=YES;
	
    //memory management
    [pool release];
	
    return success;
}

動作確認

認識されなかった検索ワードを入力してみた。

f:id:zariganitosh:20081201153718p:image

きたっ!全文検索、何でも大丈夫になった!

ヘルパーにまとめる

今まで、Spotlightプラグイン - StickiesImporter.mdimporter と、検索結果のスティッキーズデータを開くヘルパー - OpenStikies.app が二つに分かれていたけど、一つにまとめられることがわかった。

  • OpenStickies.appの「パッケージの内容を表示」して、Contentsフォルダに「Library/Spotlight/」ディレクトリを追加する。
  • その後、SpotlightプラグインをOpenStickies.app/Contents/Library/Spotlight/StickiesImporter.mdimporterとなるように移動すればOK。
  • これでOpenStikies.appを任意の場所にコピーするだけで、スティッキーズがSpotlightに対応する。
  • あっ、それとcronの設定もしておく必要があるのだった...。結局、それが一番面倒だったりして...。

直ダウンロード

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/zariganitosh/20081201/1228118653