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

# 経緯

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

# やりかた

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

```cpp
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オブジェクトを生成しておく

```cpp
	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

```cpp
// 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)を登録

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

実際に検索時に

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

みたいな感じで呼び出す

# 実験

次のようなテーブルで

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

検索してみた結果

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

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