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

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

是否有可能将通配符与UTL_MATCH.EDIT_DISTANCE函数结合使用,还是有不同(甚至更好)的方法来做到这一点?

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

PATRICK NOR
ORVILLE ALEX
OWEN TRISTAN
OKEN TRIST

查询可能看起来像OKEN*IST* ,并且应该返回OWEN TRISTAN OKEN TRISTANOKEN TRISTANOKEN将是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

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


注意你的方法在性能方面的含义。 即使“功能上”工作,使用UTL_MATCH您只能过滤内部表扫描得到的结果。
你可能需要的是这种数据的索引。
前往Oracle Text的文本索引功能。 请记住,他们需要付出一些努力才能投入工作。

你可能会fuzzy操作符,但要小心处理。 大多数oracle文本特征都是依赖于语言的(他们考虑到英语词典,德语等)。

例如

-- 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;

此查询将返回您可能会喜欢的结果(输入是字符串“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    

但是对于输入字符串“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');

后者,这个查询将很好地工作(输入是“* 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      

但随着输入“* O * TRIST *”不会返回任何东西(由于某些原因)。

底线:文字索引可能是唯一的出路(表现),但你必须小心翼翼地理解所有错综复杂的内容。

参考文献:

  • 模糊搜索:Oracle Text CONTAINS查询运算符
  • catsearch:Oracle Text SQL语句和操作符

  • 假设“通配符”表示星号,则需要与所有指定字母匹配的名称排名最高,其中指定的字母比较少匹配的更多,否则按照编辑距离相似性排序。

    使用占位符? 为您的搜索字词,请尝试以下操作:

    select *
    from mytable
    order by case
          when name like '%' || replace(?, '*', '%') || '%' then 0 - length(replace(?, '*', ''))
          else 100 - UTL_MATCH.edit_distance_similarity(?, name) end
    fetch first 10 rows
    

    仅供参考,所有“喜欢”的匹配都有一个负号,用于指定字母的数量。 所有失误都有一个非负的订货号,其百分比差异的大小。 在所有情况下,较低的数字是更好的匹配。

    链接地址: http://www.djcxy.com/p/94851.html

    上一篇: Oracle fuzzy text search with wildcards

    下一篇: Conflict Protobuf version when using Opencv and Tensorflow c++