LoginSignup
4
4

More than 5 years have passed since last update.

ICUを使ってSQLiteで曖昧検索してみる

Posted at

経緯

  1. SQLiteにはsqlite3_create_collationという文字列比較をカスタム出来る機能があるらしい
  2. ICU(International Components for Unicode)ってUnicode正規化を考慮したcollationの実装があったような・・・
  3. 曖昧検索を作ってみよう!
  4. できた → https://github.com/Nanashia/ICUandSQLiteTest (x64ビルド構成しか用意していないです)

やりかた

カスタム比較関数を定義して

int collate_CUSTOM(void* ptr, int len1, const void* ptr1, int len2, const void* ptr2) {
    // ptr1とptr2からUTF-8文字列を生成
    StringPiece s1((const char*)ptr1, len1);
    StringPiece s2((const char*)ptr2, len2);

    // 比較
    UErrorCode status;
    return ((Collator*)ptr)->compareUTF8(s1, s2, status);
}

ICUのCollatorオブジェクトを生成しておく

    UErrorCode status = U_ZERO_ERROR;
    coll = Collator::createInstance(Locale(locale_lang), status));
    if (U_FAILURE(status) || !coll) {

locale_langはCollatorオブジェクトに渡すCollation TypesとSetting Optionsを指定する
参考: http://userguide.icu-project.org/collation/customization

// Colletionの調整
// http://www.unicode.org/reports/tr35/tr35-collation.html#Collation_Settings
static const char* const locale_lang = 
    "de-u-co-phonebk"
    "-ka-shifted"     // 空白無視
    "-ks-level1";     // strength(厳密さを最もゆるく)

SQLiteにcollation用のコールバック(collate_CUSTOM)を登録

    ret = sqlite3_create_collation(db, "CUSTOM", SQLITE_UTF8, coll, collate_CUSTOM);
    if (ret) {

実際に検索時に

    SELECT * FROM tbl_example where text = 'b b' COLLATE CUSTOM;
    SELECT * FROM tbl_example order by text COLLATE CUSTOM;

みたいな感じで呼び出す

実験

次のようなテーブルで

id           text         
~~~~~~~~~~~~ ~~~~~~~~~~~~ 
1            a            
2            A            
3            Å          
4            ∀          
5            à           
6            æ           
7            Ǣ           
8            Ǟ           
9            å           
10           A          
11           a          
12           bb           
13           b b          ←間に半角スペース  
14           b  b         ←間に半角スペース  
15           b b         ←間に全角スペース 
16           b  b       ←間に全角スペース
17           b  b         ←間にタブ文字
18           b      b     ←間にタブ文字

検索してみた結果

SELECT * FROM tbl_example where text = 'a' COLLATE CUSTOM;
id           text         
~~~~~~~~~~~~ ~~~~~~~~~~~~ 
1            a            
2            A            
3            Å          
5            à           
9            å           
10           A          
11           a          
SELECT * FROM tbl_example where text = 'ae' COLLATE CUSTOM;
id           text         
~~~~~~~~~~~~ ~~~~~~~~~~~~ 
6            æ           
7            Ǣ           
8            Ǟ           
SELECT * FROM tbl_example where text = 'b b' COLLATE CUSTOM;
id           text         
~~~~~~~~~~~~ ~~~~~~~~~~~~ 
12           bb           
13           b b          
14           b  b         
15           b b        
16           b  b     
17           b  b          
18           b      b         
SELECT * FROM tbl_example order by text COLLATE CUSTOM;
id           text         
~~~~~~~~~~~~ ~~~~~~~~~~~~ 
4            ∀          
1            a            
2            A            
3            Å          
5            à           
9            å           
10           A          
11           a          
6            æ           
7            Ǣ           
8            Ǟ           
12           bb           
13           b b          
14           b  b         
15           b b        
16           b  b     
17           b  b          
18           b      b         

なんとなく曖昧な感じで検索できている気がする
パフォーマンス面は検証が面倒なので察してください

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4