経緯
MySQLでの全文検索用をしたかったので知らべていたところ以下の記事
でNgram(バイグラム)の実装が必要になりそうだったので作成してみました。
MYSQL5.7以降だと既に日本語のNgramパーサーが入っているそうなのでMYSQL5.7以降はこちら。
但しこんな動作もあるらしいです。
以下の設定は忘れやすいので注意
[mysqld]
innodb_ft_min_token_size=2
概要
CMSでhtmlを保存するのとは別に検索用カラムを用意して検索用文字列として使用する想定です。
コード
class Bigram
{
/**
* 文字列を登録・検索用バイグラムに変換する
*
* @param string|null $string
* @param boolean $for_search_flag
* false:DB保存時に使用する変換方法 あいう→あい いう う
* true:検索時に使用する変換方法 あいう→あい いう 1文字の場合は空文字を返します(そもそも2文字以上で検索しないとヒットしないので構わない)
* @return string|null
*/
public function convert_to_bigram(string $string = null, bool $for_search_flag = false)
{
if (is_null($string))
{
return null;
}
$string = str_replace(array(" ", " ", "\r", "\n", "\t"), "", $string);
$string = strip_tags($string);
$character_list = preg_split("//u", $string, -1, PREG_SPLIT_NO_EMPTY);// 1文字づつ配列に分ける
$bigram = '';// バイグラム
$glue = '';
foreach ($character_list as $index => $character)
{
if (isset($character_list[$index + 1]))
{
$bigram .= $glue.$character.$character_list[$index + 1];
}
else
{
if ($for_search_flag === false)
{
$bigram .= $glue.$character;
}
}
$glue = ' ';
}
return $bigram;
}
}
$string = "<p><div><a>あ い\t う え\nおか</a></div></p>";
$bigram = new Bigram();
var_dump($bigram->convert_to_bigram($string));
var_dump($bigram->convert_to_bigram($string, true));
結果
string(38) "あい いう うえ えお おか か"
string(34) "あい いう うえ えお おか"
確認
その他
for_search_flagで結果を分けたのは検索時用のバイグラムが必要になったためです。
※バイグラムで検索する際は2文字以上で検索すること
「あいうえおか」から「うえお」で検索する例
DBで持つのは「あい いう うえ えお おか か」
match(`bigram`) against('+"うえ えお" in boolean mode')
ではヒットするが
match(`bigram`) against('+"うえ えお お" in boolean mode')
だとヒットしない