使用通配符进行Oracle模糊文本搜索

Flo*_*ian 7 oracle fuzzy-search edit-distance wildcard

我有一个充满客户数据的SAP Oracle数据库.在我们的自定义CRM中,使用通配符搜索客户是很常见的.除了SAP标准搜索之外,我们还想对一些类似于输入名称的名称进行模糊文本搜索.目前我们正在使用该UTL_MATCH.EDIT_DISTANCE功能搜索相似的名称.唯一的缺点是不可能使用一些通配符模式.

是否有可能将通配符与UTL_MATCH.EDIT_DISTANCE函数结合使用,或者有不同(甚至更好)的方法吗?

比方说,数据库中有以下名称:

PATRICK NOR
ORVILLE ALEX
OWEN TRISTAN
OKEN TRIST
Run Code Online (Sandbox Code Playgroud)

查询可能看起来像OKEN*IST*两个OWEN TRISTAN并且OKEN TRISTAN应该返回.OKEN将是100%匹配,OWEN更少.

我当前的测试查询看起来像:

SELECT gp.partner, gp.bu_sort1, UTL_MATCH.edit_distance(gp.bu_sort1, ?) as edit_distance, 
      FROM but000 gp
      WHERE UTL_MATCH.edit_distance(gp.bu_sort1, ?) < 4
Run Code Online (Sandbox Code Playgroud)

此查询工作正常,除非*在搜索字符串中使用通配符(这很常见).

Ant*_*nio 3

请注意您的方法对性能的影响。即使它“功能上”有效,UTL_MATCH您也只能过滤通过内部表扫描获得的结果。
您可能需要的是此类数据的索引。
前往 Oracle Text,这是 Oracle 的文本索引功能。请记住,它们需要付出一些努力才能发挥作用。

您可能会与操作员周旋fuzzy,但请小心操作。大多数预言机文本功能都依赖于语言(它们考虑了英语词典、德语等)。

例如

-- create and populate the table
create table xxx_names (name varchar2(100));

insert into xxx_names(name) values('PATRICK NOR');
insert into xxx_names(name) values('ORVILLE ALEX');
insert into xxx_names(name) values('OWEN TRISTAN');
insert into xxx_names(name) values('OKEN TRIST');
insert into xxx_names(name) values('OKENOR SAD');
insert into xxx_names(name) values('OKENEAR TRUST');

--create the domain index
create index xxx_names_ctx on xxx_names(name) indextype is ctxsys.context;
Run Code Online (Sandbox Code Playgroud)

此查询将返回您可能想要的结果(输入是字符串“TRST”)

select
  SCORE(1), name
from
  xxx_names n
where
  CONTAINS(n.name, 'definescore(fuzzy(TRST, 1, 6, weight),relevance)', 1) > 0
; 



  SCORE(1) NAME               
---------- --------------------
         1 OWEN TRISTAN        
        22 OKEN TRIST    
Run Code Online (Sandbox Code Playgroud)

但对于输入字符串“IST”,它可能不会返回任何内容(在我的例子中,这就是它的作用)。另请注意,一般情况下,少于 3 个字符的输入默认被视为不匹配。
如果您取消“模糊”要求并坚持查找仅“包含”您传入的确切序列的行,您可能会得到更“可预测”的结果。
在这种情况下,请尝试使用ctxcat索引,顺便说一下支持一些通配符(警告:支持多列,但一列的大小不能超过30个字符!)

-- create and populate the table
--max length is 30 chars, otherwise the catsearch index can't be created
create table xxx_names (name varchar2(30));

insert into xxx_names(name) values('PATRICK NOR');
insert into xxx_names(name) values('ORVILLE ALEX');
insert into xxx_names(name) values('OWEN TRISTAN');
insert into xxx_names(name) values('OKEN TRIST');
insert into xxx_names(name) values('OKENOR SAD');
insert into xxx_names(name) values('OKENEAR TRUST');

begin

ctx_ddl.create_index_set('xxx_names_set');
ctx_ddl.add_index('xxx_names_set', 'name'); 

end;
/

drop index xxx_names_cat;
CREATE INDEX xxx_names_cat ON xxx_names(name) INDEXTYPE IS CTXSYS.CTXCAT
PARAMETERS ('index set xxx_names_set');
Run Code Online (Sandbox Code Playgroud)

后者,使用此查询可以很好地工作(输入是“*TRIST*”)

select
  UTL_MATCH.edit_distance(name, 'TRIST') dist,
  name
from
  xxx_names
where
  catsearch(name, '*TRIST*', 'order by name desc') > 0
;

      DIST NAME               
---------- --------------------
         7 OWEN TRISTAN        
         5 OKEN TRIST      
Run Code Online (Sandbox Code Playgroud)

但输入“*O*TRIST*”不会返回任何内容(由于某些原因)。

底线:文本索引可能是唯一的方法(为了性能),但你必须花很多功夫才能理解所有的复杂性。

参考: