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

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

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

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

Q&A

2回答

2120閲覧

MySQLの全文検索で意図しない行まで取得されてしまう

janak

総合スコア0

MySQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

0グッド

1クリップ

投稿2020/10/03 05:32

編集2020/10/04 08:06

SQL

1CREATE TABLE industries ( 2 code INT PRIMARY KEY, 3 name VARCHAR(255) NOT NULL, 4 FULLTEXT INDEX idx (name) WITH PARSER ngram 5); 6 7Query OK, 0 rows affected (0.56 sec) 8 9 10INSERT INTO industries VALUES 11(1, '鉄鋼業'), 12(2, '非鉄金属工業'), 13(3, '鉄鋼・非鉄金属工業'), 14(4, '情報通信業'); 15 16Query OK, 4 rows affected (0.21 sec) 17Records: 4 Duplicates: 0 Warnings: 0 18 19 20SELECT * FROM industries WHERE 21MATCH (name) AGAINST ('鉄鋼・非鉄金属' IN BOOLEAN MODE); 22 23+------+-----------------------------+ 24| code | name | 25+------+-----------------------------+ 26| 3 | 鉄鋼・非鉄金属工業 | 27| 2 | 非鉄金属工業 | 28| 1 | 鉄鋼業 | 29+------+-----------------------------+ 303 rows in set (0.01 sec) 31

MySQLのバージョンは8.0.12です。

上記のテーブルで、name列に「鉄鋼・非鉄金属」を含む行のみを取得したいのですが、意図しない他の行まで取得されてしまいます。(「鉄鋼・非鉄金属工業」の行のみ取得したいです。)

LIKE演算子など他の手法ではなく、全文検索で該当行のみ取得する方法を教えて頂きたいです。区切り文字の「・」が余計な挙動を引き起こしているのでしょうか?

よろしくお願いします。

(2020/10/03 追記)
ちなみに、以下の方法では解決できませんでした。

SQL

1SELECT * FROM industries WHERE 2MATCH (name) AGAINST ('"鉄鋼・非鉄金属"' IN BOOLEAN MODE); 3 4Empty set (0.01 sec)

参考
MySQL公式ドキュメント 12.9.2 ブール全文検索

(2020/10/04 追記)
回答欄に記した通り、NATURAL LANGUAGE MODEを使うことで、ひとまず問題は解決しております。
しかし、BOOLEAN MODEで中点(・)などの記号が文字として認識されないという根本的な問題は解決しておりませんので、わかる方がいらしたらご回答をよろしくお願いします。

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

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

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

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

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

kuma_kuma_

2020/10/03 05:53

実際に実行されたSQLおよびその実行した結果の追記をおねがいします。
janak

2020/10/03 06:08

失礼しました。実行結果が一部未記載でしたので追記致しました。
kuma_kuma_

2020/10/03 06:51

こちらにMySQLが無い為こちらに記載しますが SELECT * FROM industries WHERE MATCH (name) AGAINST ('"鉄鋼・非鉄金属"' IN BOOLEAN MODE); では結果どうなりますか?
janak

2020/10/03 06:59

kuma_kuma_さん そのクエリは試しましたが、結果は何も返ってきませんでした。
kuma_kuma_

2020/10/03 07:27

申し訳ないのですが SELECT * FROM industries WHERE MATCH (name) AGAINST ('"鉄鋼・非鉄金属工業"' IN BOOLEAN MODE); ではどうですか?
janak

2020/10/04 00:35

hihijijiさん 照合順序についてあまり詳しくないのですが、_csに設定すると大文字と小文字が区別されるようですね。SQLでは「大文字と小文字は区別しない」というのが暗黙的なルールになっている面があるので、できればそのような設定は避けたいですね…
janak

2020/10/04 00:35

kuma_kuma_さん そちらのクエリも結果はEmptyになってしまいます…
guest

回答2

0

回答してくださった方達を参考に自分なりに調べた結果、問題の原因は中点(・)が文字として扱われていないということのようです。
この問題を解決する簡単な方法の一つは、BOOLEAN MODEではなく、NATURAL LANGUAGE MODEで全文検索をすることです。以下のように類似度が最も高くなります。

SQL

1SELECT code, name, 2MATCH (name) AGAINST ('鉄鋼・非鉄金属工業' IN NATURAL LANGUAGE MODE) AS score 3FROM industries; 4 5+------+-----------------------------+----------------------+ 6| code | name | score | 7+------+-----------------------------+----------------------+ 8| 1 | 鉄鋼業 | 0.015609688125550747 | 9| 2 | 非鉄金属工業 | 0.07804843783378601 | 10| 3 | 鉄鋼・非鉄金属工業 | 0.8186105489730835 | 11| 4 | 情報通信業 | 0 | 12+------+-----------------------------+----------------------+ 134 rows in set (0.00 sec) 14

確かに、BOOLEAN MODEでも類似度は高くなります。

SQL

1SELECT code, name, 2MATCH (name) AGAINST ('鉄鋼・非鉄金属工業' IN BOOLEAN MODE) AS score 3FROM industries; 4 5+------+-----------------------------+----------------------+ 6| code | name | score | 7+------+-----------------------------+----------------------+ 8| 1 | 鉄鋼業 | 0.009391550906002522 | 9| 2 | 非鉄金属工業 | 0.04695775359869003 | 10| 3 | 鉄鋼・非鉄金属工業 | 0.05634930357336998 | 11| 4 | 情報通信業 | 0 | 12+------+-----------------------------+----------------------+ 134 rows in set (0.00 sec)

しかし、極端な例かも知れませんが「鉄鋼、非鉄金属工業」や「鉄鋼 非鉄金属工業」などのレコードがあった場合、BOOLEAN MODEでは中点(・)が文字として認識されていない以上同じ類似度になってしまいます。

SQL

1SELECT code, name, 2MATCH (name) AGAINST ('鉄鋼・非鉄金属工業' IN BOOLEAN MODE) AS score 3FROM industries; 4 5+------+-----------------------------+----------------------+ 6| code | name | score | 7+------+-----------------------------+----------------------+ 8| 1 | 鉄鋼業 | 0.004481872543692589 | 9| 2 | 非鉄金属工業 | 0.022409362718462944 | 10| 3 | 鉄鋼・非鉄金属工業 | 0.026891235262155533 | 11| 4 | 情報通信業 | 0 | 12| 5 | 鉄鋼、非鉄金属工業 | 0.026891235262155533 | 13| 6 | 鉄鋼 非鉄金属工業 | 0.026891235262155533 | 14+------+-----------------------------+----------------------+ 156 rows in set (0.01 sec) 16

NATURAL LANGUAGE MODEの場合。

SQL

1SELECT code, name, 2MATCH (name) AGAINST ('鉄鋼・非鉄金属工業' IN NATURAL LANGUAGE MODE) AS score 3FROM industries; 4 5+------+-----------------------------+----------------------+ 6| code | name | score | 7+------+-----------------------------+----------------------+ 8| 1 | 鉄鋼業 | 0.015609688125550747 | 9| 2 | 非鉄金属工業 | 0.07804843783378601 | 10| 3 | 鉄鋼・非鉄金属工業 | 1.304697036743164 | 11| 4 | 情報通信業 | 0 | 12| 5 | 鉄鋼、非鉄金属工業 | 0.09365812689065933 | 13| 6 | 鉄鋼 非鉄金属工業 | 0.09365812689065933 | 14+------+-----------------------------+----------------------+ 156 rows in set (0.00 sec)

ただ、NATURAL LANGUAGE MODEではBOOLEAN MODEでは行える「+」や「-」などのクエリが使えなくなるのがデメリットだと思います。BOOLEAN MODEでも中点などの記号を文字として認識させる方法がもしあれば教えて頂きたいです。

(参考)
MySQL公式ドキュメント 12.9.4 全文ストップワード

「ストップワードリストは自由形式で、改行、空白、カンマなどの英数字以外の文字でストップワードが区切られます。例外として、下線文字 (「_」) と単一アポストロフィー (「'」) は単語の一部として処理されます。ストップワードリストの文字セットは、サーバーのデフォルト文字セットです。セクション10.1.3.1「サーバー文字セットおよび照合順序」を参照してください。」

投稿2020/10/04 00:30

janak

総合スコア0

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

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

kuma_kuma_

2020/10/04 01:37

うまく動くか不安ですが SELECT code, name, MATCH (replace(name, "・", "30fb")) AGAINST ('鉄鋼30fb非鉄金属' IN NATURAL mode MODE) AS score FROM industries; で試してみて下さい。
sazi

2020/10/04 02:26

解決済みにしたのなら、文中で質問するのではなく、新たに質問した方が良いと思いますよ。
kuma_kuma_

2020/10/04 03:55

saziさん 私も以前この様な事があったとき「新たに質問した方が良い」と書いたのですが 他の方から「2重の質問になるから解決済みを撤回したほうが良い」と指摘されました。 よって「解決済みを撤回」をオススメします。
sazi

2020/10/04 05:20

@kuma_kuma_さん 内容的に続いてますので、私もこの質問での継続を薦めます。 解決済みのままだと、多分他の回答者の目にとまらないと思いますので、解決済みにしたいのなら、という事でコメントしました。
kuma_kuma_

2020/10/04 05:24

saziさん 了解しました。 自分の時はすごい勢いでおこられました為、書かせていただいた次第です。
janak

2020/10/04 07:58

kuma_kuma_さん、saziさん アドバイスありがとうございます、未解決に戻します。
guest

0

中点(・)が文字として扱われていない動作ですね。
12.9.1 自然言語全文検索

MySQL FULLTEXT の実装では、トゥルーワード文字 (文字、数字、およびアンダースコア) のシーケンスが単語とみなされます。

若しくはストップワードとして登録されたりしていませんか?

積極的ではありませんが、中点を含む場合にはそれぞれを単語として検索するとか

SQL

1SELECT * FROM industries WHERE 2MATCH (name) AGAINST ('+鉄鋼 +非鉄金属' IN BOOLEAN MODE)

投稿2020/10/03 10:05

sazi

総合スコア25327

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

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

janak

2020/10/04 00:39

ご回答ありがとうございます。 おっしゃる通り、中点が文字として認識されていないようですね。 INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORDで確認したところ、ストップワードには登録されていませんでした。(初期設定のまま) システム変数のft_stopword_fileを「''」に設定することも試しましたが、解決しませんでした。
sazi

2020/10/04 02:33

後は、検索している中点と登録されている中点が同じかどうかですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問