質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

Q&A

解決済

1回答

1298閲覧

MySQLの「FULLTEXT INDEX」を用いて、一定以上の類似だけを取得したい

souseki

総合スコア1

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

0グッド

0クリップ

投稿2021/12/31 17:44

編集2022/01/01 07:37

前提・実現したいこと

MySQLの「FULLTEXT INDEX」を利用し、類似のコンテンツに対し「すでに類似がありますよ」というレスポンスを表示することを目指しています。

類似スコアの算定は「AGAINST、MATCH」で実装しました。

発生している問題

吾輩は猫である
というデータに対し、

吾輩は、猫である
と言う風にを加えて検索すると、類似スコアが「0」になるという問題に苦慮しています。

明らかに(我々人間にとっては)類似性が高いのに、なんとかならないでしょうか…

該当のソースコード

以下の設計となっています。

MySQL

1-- 2-- テーブルの構造 `contents` 3-- 4CREATE TABLE IF NOT EXISTS `contents` ( 5 `ID` bigint(20) unsigned NOT NULL, 6 `content` varchar(1000) CHARACTER SET utf8mb4 NOT NULL 7) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; 8 9-- 10-- テーブルのデータのダンプ `contents` 11-- 12INSERT INTO `contents` (`ID`, `content`) VALUES 13(1, '智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。'), 14(2, '吾輩は猫である。'), 15(3, '吾輩は猫である。名前はまだ無い。どこで生れたか頓(とん)と見當がつかぬ。'), 16(4, 'きょう、ママンが死んだ。 もしかすると、昨日かも知れないが、私にはわからない。');

類似スコアが「0」になるという問題のコードはこちらです。

MySQL

1# score = 0 2SELECT ID, content, MATCH (content) 3AGAINST( 4 '吾輩は、猫である。' 5 IN NATURAL LANGUAGE MODE 6) AS score 7FROM contents

試したこと

長い文字数ではがあるだけの違いでも十分に類似性が高い値となりました。

例えば ID=1 の
智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。

というデータに対し、同じようにを1つ加えて
智に働けば、角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。

とすると、スコアは「1.465677261352539」となります。

# score = 1.465677261352539 SELECT ID, content, MATCH (content) AGAINST( '智に働けば、角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。' IN NATURAL LANGUAGE MODE ) AS score FROM contents

この違いから、「類似スコアを、文字数の逆数の2乗する」などのように後から指数関数的に大きく倍すれば、文字数が短いものでも大きな類似スコアとなるか?とも考えましたが、結局「0」にいくつかけても「0」なのでこのままでは難しそうです。

なのでもし類似スコアの小数点をもっと小さく(現状0と表示されているその先まで)表示する方法があれば…、と考えた経緯から、質問を投稿させていただく運びとなった次第でございます。

または全ての類似スコアを全体的に底上げする方法があれば…とも考えられます。

もちろんこれらの方法に留まらず、「すでに類似がありますよ」というレスポンスを表示する。という目的に適った別のアプローチも募集させて頂ければ幸いです。

補足情報(FW/ツールのバージョンなど)

MySQLのバージョンは5.7.31 で、Xサーバーの利用になります。

ご回答どうぞ宜しくお願い致します。

###追記
検索用文字列を追加してみてはどうかと思いました、が、本来の文字列との類似性よりも、検索用文字列との類似性の方のスコアが色濃く出てしまい使えませんでした。こうです。

まず検索用文字列として__MY_FULLTEXT__この文は検索用ですを追加します。

MySQL

1UPDATE contents 2SET content = CONCAT(content, '__MY_FULLTEXT__この文は検索用です')

そして検索します。

MySQL

1SELECT ID, content, MATCH (content) 2AGAINST( 3 '吾輩は、猫である。__MY_FULLTEXT__この文は検索用です' 4 IN NATURAL LANGUAGE MODE 5) AS score 6FROM contents

これにより ID=2 の
吾輩は猫である。__MY_FULLTEXT__この文は検索用です
の類似スコアが「0.25517651438713074」と上昇しましたが、

反面で ID=1 の
智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。__MY_FULLTEXT__この文は検索用です
もまた「0.25517651438713074」になってしまいました。

つまり本来の文字列との類似性よりも、検索用文字列との類似性の方のスコアが色濃く出てしまったらしく、これでは目的を果たすことはできませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

提示のソースコードからはFULLTEXTインデックスをどう追加したのかよく分かりませんでしたが、おそらくngram(bigram)にしていなかったので、表記ゆれに対応できないということだと思います(デフォルトはかなり荒い文字の区切り方をするようでした)。

sql

1-- 2-- 元のcreate tableからは、FULLTEXTの追加など動作確認用に改変しました 3-- 4CREATE TABLE IF NOT EXISTS `contents` ( 5 `ID` bigint unsigned PRIMARY KEY, 6 `content` varchar(1000) CHARACTER SET utf8mb4 NOT NULL, 7 FULLTEXT (content) WITH PARSER ngram 8) ENGINE=InnoDB; 9 10INSERT INTO `contents` (`ID`, `content`) VALUES 11(1, '智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。'), 12(2, '吾輩は猫である。'), 13(3, '吾輩は猫である。名前はまだ無い。どこで生れたか頓(とん)と見當がつかぬ。'), 14(4, 'きょう、ママンが死んだ。 もしかすると、昨日かも知れないが、私にはわからない。');

このテーブルに関して、問題のSQLは非ゼロのスコアを返すようです。

mysql> SELECT ID, content, MATCH (content) -> AGAINST( -> '吾輩は、猫である。' -> IN NATURAL LANGUAGE MODE -> ) AS score -> FROM contents -> \G *************************** 1. row *************************** ID: 1 content: 智に働けば角が立つ。情に棹させば流される。意地を通せば窮屈だ。兎角に人の世は住みにくい。 score: 0.015609688125550747 *************************** 2. row *************************** ID: 2 content: 吾輩は猫である。 score: 0.4687049686908722 *************************** 3. row *************************** ID: 3 content: 吾輩は猫である。名前はまだ無い。どこで生れたか頓(とん)と見當がつかぬ。 score: 0.4687049686908722 *************************** 4. row *************************** ID: 4 content: きょう、ママンが死んだ。 もしかすると、昨日かも知れないが、私にはわからない。 score: 0 4 rows in set (0.00 sec)

投稿2022/01/01 12:17

saka1

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

souseki

2022/01/01 13:15

仰る通りでした。今回FULLTEXTインデックスはあとからALTER TABLEしたのですが、その際に「WITH PARSER ngram」を記述しておらず、改めて記述したインデックスを再構築しましたところ解決できました。ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問