DBから抽出したレコードを指定キーワード(複数)で絞り込むロジックについて

投稿者: Anonymous

例として掲示板システムで”コメント”テーブルから新規10件を表示、
但し”NGワード”テーブル(1レコード1NGワードを保持)にあるNGワードが含まれるコメントは
除外したい、というケースを想定して下さい。

NGワードは複数あります。
このようなケースでなるべくコストの少ない検索方法を模索しているのですが
何か良い方法は無いでしょうか。

追加:可能であればNGなコメントも取得自体はしておいてNGであるという状態を持ちたいです。
となるとNGワードテーブルを結合してそのIDがNULLかどうか、という方法しか無さそうですが・・

解決

「なるべくコストが少ない検索方法」とのことですが、用途的にRDBMSがあまり得意としない処理のような気がします。
とりあえずこんな感じで実装して、パフォーマンスが怪しくなってきたときに全文検索エンジンの導入等を検討してみるのはどうでしょうか。

DATA

create table blogs (
  title varchar(100),
  content text
  );

create table ng_words (
  word varchar(100)
  );

insert into blogs values ('blog1', 'Lorem ipsum dolor sit amet, vix in tantas officiis, pro.');
insert into blogs values ('blog2', 'Lorem ipsum dolor sit amet, veri scripserit adversarium in vix.');
insert into blogs values ('blog3', 'Lorem ipsum dolor sit amet, ad virtute sententiae neglegentur vel.');
insert into blogs values ('blog4', 'Lorem ipsum dolor sit amet, ad sea nisl aliquip deseruisse.');
insert into blogs values ('blog5', 'Lorem ipsum dolor sit amet, quo elitr aperiri tractatos id.');
insert into blogs values ('blog6', 'Lorem ipsum dolor sit amet, alienum insolens eleifend id has.');

insert into ng_words values ('vel'); -- remove blog3
insert into ng_words values ('quo'); -- remove blog5

SQL

SELECT b.* 
FROM   blogs b 
WHERE  NOT EXISTS(SELECT * 
                  FROM   ng_words n 
                  WHERE  b.content LIKE Concat('%', n.word, '%')) 
ORDER  BY b.title 
LIMIT  3 

RESULT

画像の説明をここに入力

なお、このコードの実行結果はこちらで確認できます。

http://sqlfiddle.com/#!9/7dea4/4

追記

unarist さんのコメントを受けて作った、LIKEではなくPOSITIONを使うバージョンです。
POSITIONを使うと、 % のような「LIKEで特殊な意味を持つ文字」も検索できるようになります。

DATA

create table blogs (
  title varchar(100),
  content text
  );

create table ng_words (
  word varchar(100)
  );

insert into blogs values ('blog1', 'Lorem ipsum dolor sit amet, vix in tantas officiis, pro.');
insert into blogs values ('blog2', 'Lorem ipsum dolor sit amet, veri scripserit adversarium in vix.');
insert into blogs values ('blog3', 'Lorem ipsum dolor sit amet, ad virtute sententiae neglegentur %vel.');
insert into blogs values ('blog4', 'Lorem ipsum dolor sit amet, ad sea nisl aliquip deseruisse.');
insert into blogs values ('blog5', 'Lorem ipsum dolor sit amet, %quo elitr aperiri tractatos id.');
insert into blogs values ('blog6', 'Lorem ipsum dolor sit amet, alienum insolens eleifend id has.');

insert into ng_words values ('%v'); -- remove blog3
insert into ng_words values ('quo'); -- remove blog5

SQL

SELECT b.* 
FROM   blogs b 
WHERE  NOT EXISTS(SELECT * 
                  FROM   ng_words n 
                  WHERE  POSITION(n.word IN b.content) != 0) 
ORDER  BY b.title 
LIMIT  3 

RESULT

画像の説明をここに入力

コード

http://sqlfiddle.com/#!9/f0891/1

LIKEを使った場合のRESULT

画像の説明をここに入力

LIKEの場合のコード

http://sqlfiddle.com/#!9/f0891/3

回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *