PostgreSQL多词匹配:Java实现商标黑名单检测方案问询
问题描述
我有如下用于存储词汇的PostgreSQL表:
CREATE TABLE IF NOT EXISTS words ( id bigint NOT NULL DEFAULT nextval('processed_words_id_seq'::regclass), keyword character varying(300) COLLATE pg_catalog."default", ); insert into words (keyword) VALUES ('while swam is interesting', 'ibm is a company like bmw'); CREATE TABLE IF NOT EXISTS trademarks ( id bigint NOT NULL DEFAULT nextval('trademarks_id_seq'::regclass), trademark character varying(300) COLLATE pg_catalog."default", ); insert into trademarks (trademark) VALUES ('swam', 'ibm', 'bmw');
注:修正了原插入语句的表名错误,原insert into words (trademarks)应为insert into trademarks (trademark)
trademarks表中存储数千个已注册的商标名称,需要检测words表的keyword字段内容是否包含单个词汇或词汇组形式的商标。比如words.keyword中的while swam is interesting要能匹配到trademarks里的swam,ibm is a company like bmw要能匹配到ibm和bmw。
现有Java代码只能匹配完整字符串,无法实现单词/短语的匹配,代码如下:
Optional<ProcessedWords> keywords = processedWordsService.findRandomKeywordWhereTrademarkBlacklistedIsEmpty(); if(keywords.isPresent()) { List<BlacklistedWords> blacklistedWords = blacklistedWordsService.findAll(); List<String> list = new ArrayList<>(); for(BlacklistedWords item: blacklistedWords){ list.add(item.getKeyword()); } ProcessedWords processedWords = keywords.get(); String keyword = processedWords.getKeyword(); if(list.contains(keyword)) { System.out.println("Found blacklisted word in keyword: " + keyword); } } @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder(toBuilder = true) @Entity @Table(name = "trademarks") public class BlacklistedWords implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, updatable = false, nullable = false) private long id; @Column(name = "trademark", length = 200, unique = true) private String keyword; }
解决方案
方法一:Java端实现单词/短语匹配
思路
- 将商标列表转换为正则表达式,为每个商标添加单词边界规则,避免部分字符匹配(比如防止
swam匹配swamp)。 - 用正则匹配目标字符串,提取所有匹配的商标。
修改后的代码
Optional<ProcessedWords> keywords = processedWordsService.findRandomKeywordWhereTrademarkBlacklistedIsEmpty(); if (keywords.isPresent()) { List<BlacklistedWords> blacklistedWords = blacklistedWordsService.findAll(); // 构建正则表达式:匹配完整单词/短语,转义特殊字符避免正则语法冲突 String regexPattern = blacklistedWords.stream() .map(item -> "\\b" + Pattern.quote(item.getKeyword()) + "\\b") .collect(Collectors.joining("|")); Pattern pattern = Pattern.compile(regexPattern, Pattern.CASE_INSENSITIVE); // 可选忽略大小写 ProcessedWords processedWords = keywords.get(); String keywordContent = processedWords.getKeyword(); Matcher matcher = pattern.matcher(keywordContent); // 遍历所有匹配到的商标 while (matcher.find()) { String matchedTrademark = matcher.group(); System.out.println("Found blacklisted trademark: " + matchedTrademark + " in content: " + keywordContent); // 可添加后续处理逻辑,比如标记该词汇为包含黑名单商标 } }
说明
\\b代表单词边界,确保匹配的是完整的单词或短语。Pattern.quote()用于转义商标中的特殊字符(如.,*等正则符号),避免匹配逻辑出错。Pattern.CASE_INSENSITIVE为可选配置,可实现大小写不敏感匹配,根据业务需求调整。
方法二:数据库端直接查询(更高效)
思路
如果trademarks表数据量较大(数千条),将所有数据拉取到Java端处理会影响性能,直接在数据库层做关联查询效率更高。
实现方式
方式1:使用PostgreSQL的LIKE查询(适合简单单词匹配)
修改processedWordsService的查询方法,直接在SQL中关联两张表:
SELECT w.*, t.trademark FROM words w JOIN trademarks t ON w.keyword LIKE '% ' || t.trademark || ' %' OR w.keyword LIKE t.trademark || ' %' OR w.keyword LIKE '% ' || t.trademark OR w.keyword = t.trademark WHERE w.trademark_blacklisted IS NULL;
注:trademark_blacklisted对应原代码中findRandomKeywordWhereTrademarkBlacklistedIsEmpty()的过滤字段,需根据实际表结构调整
方式2:使用PostgreSQL的正则表达式查询
SELECT w.*, t.trademark FROM words w JOIN trademarks t ON w.keyword ~* ('\m' || t.trademark || '\M') WHERE w.trademark_blacklisted IS NULL;
~*表示大小写不敏感的正则匹配\m是PostgreSQL的单词起始边界,\M是单词结束边界,作用等同于Java中的\\b
Java端直接获取匹配结果即可:
List<ProcessedWordsWithTrademark> matchedRecords = processedWordsService.findKeywordsWithBlacklistedTrademarks(); for (var record : matchedRecords) { System.out.println("Found trademark: " + record.getTrademark() + " in keyword: " + record.getKeyword()); }
性能优化建议
- 若trademarks表数据持续增长,建议给
trademarks.trademark字段添加索引,或使用PostgreSQL的全文检索功能(创建tsvector索引)提升查询效率。 - 采用Java端处理时,建议缓存商标列表(如使用Guava Cache或Spring Cache),避免每次查询都从数据库拉取数据。
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

