微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sql – 查询数据库名称的建议

我有一个Oracle数据库,像许多人一样,有一个包含传记信息的表.在这里,我想以“自然”的方式用名字搜索.

该表有名字和姓氏字段,目前我正在使用这样的东西:

select id,forename,surname
from   mytable
where  upper(forename) like '%JOHN%'
and    upper(surname) like '%sMITH%';

这是有效的,但它可能非常慢,因为这个表上的索引显然不能说明前面的通配符.此外,用户通常会根据他们通过电话告诉他们 – 包括大量的非英文名称 – 寻找人,因此也可以做一些语音分析.

因此,我一直在尝试使用Oracle Text:

create index forenameFTX on mytable(forename) indextype is ctxsys.context;
create index surnameFTX on mytable(surname) indextype is ctxsys.context;

select   score(1)+score(2) relevance,id,surname
from     mytable
where    contains(forename,'!%john%',1) > 0
and      contains(surname,'!%smith%',2) > 0
order by relevance desc;

这具有使用Soundex算法以及全文索引的优点,因此应该更有效率. (虽然,我的轶事结果显示它很慢!)我唯一的担心是:

>首先,文本指标需要以有意义的方式进行刷新.在提交时使用会太慢,可能会干扰前端软件(无法控制的)与数据库的交互;所以需要一些思考…
> Oracle返回的结果并不是完全自然的排序;我不太确定这个分数功能.例如,我的发展数据显示“乔纳森·彼得·杰森·史密斯”在顶级,而“简·玛格丽特·辛普森”与“约翰·特伦斯·史密斯”

我认为删除前面的通配符可能会提高性能,而不会降低结果,因为在现实生活中,您永远不会在名称中间搜索一个块.但是,否则,我开放的想法…这种情况必须已经实施了恶心!任何人都可以提出一个更好的做法,我正在做什么/现在考虑?

谢谢 :)

解决方法

我提出了一个非常好的解决方案,遵循评论中的建议.特别是@ X-Zero建议创建一个Soundexes表:在我的情况下,我可以创建新的表,但不允许改变现有的模式!

所以我的过程如下:

>创建一个带有列的新表:ID,令牌,声音和位置;主键(ID,声音,位置)和附加索引(ID,声音).
>通过传记表中的每个人:

连接他们的姓和姓.
>将代码页更改为us7ascii,因此重音字符将被归一化.这是因为Soundex算法不适用于重音字符.
>将所有非字母字符转换为空格,并将其视为令牌之间的边界.
>标记此字符串并将表单插入到小写字母表中,令牌的Soundex和令牌来自原始字符串的位置;将此与ID相关联.

像这样:

declare
  nameString varchar2(82);
  token varchar2(40);
  posn integer;
  cursor myNames is
    select id,forename||' '||surname person_name
    from   mypeople;
begin
  for person in myNames
  loop
    nameString := trim(
                    utl_i18n.escape_reference(
                      regexp_replace(
                        regexp_replace(person.person_name,'[^[:alpha:]]',' '),'\s+','us7ascii')
                    )||' ';
    posn := 1;
    while nameString is not null
    loop
      token := substr(nameString,1,instr(nameString,' ') - 1);
      insert into personsearch values (person.id,lower(token),soundex(token),posn);
      nameString := substr(nameString,' ') + 1);
      posn := posn + 1;
    end loop;
  end loop;
end;
/

所以,例如,“Si’n O’Conner”被标记为“sian”(位置1),“o”(位置2)和“conner”(位置3),并且这三个条目与它们的Soundex一起插入到个人搜索以及他们的身份证.

>要搜索,我们执行相同的过程:令牌搜索条件,然后返回Soundexes和相对位置匹配的结果.我们按照位置顺序排列,然后依次对原始搜索的每个令牌的Levenshtein距离(ld)进行排序.

例如,该查询搜索两个令牌(即,预先标记符的搜索字符串):

with     searchcriteria as (
         select 'john'  token1,'smith' token2
         from   dual)
select   alpha.id,mypeople.forename||' '||mypeople.surname
from     peoplesearch alpha
join     mypeople
on       mypeople.student_id = alpha.student_id
join     peoplesearch beta
on       beta.student_id = alpha.student_id
and      beta.position   > alpha.position
join     searchcriteria
on       1 = 1
where    alpha.sound = soundex(searchcriteria.token1)
and      beta.sound  = soundex(searchcriteria.token2)
order by alpha.position,ld(alpha.token,searchcriteria.token1),beta.position,ld(beta.token,searchcriteria.token2),alpha.student_id;

为了搜索任意数量的令牌,我们需要使用动态sql:连续搜索表与令牌一样多次,连接表中的位置字段必须大于先前连接的表的位置.我打算写一个函数来做这个 – 以及搜索字符串tokenisation – 这将返回一个ID表.但是,我刚刚发布在这里,所以你得到的想法:)

正如我所说,这样做很好:它很快返回好的结果.即使是搜索“John Smith”,一旦被服务器缓存,运行时间不到0.2s;返回超过200行…我很高兴与它,并将寻求投入生产.唯一的问题是:

>令牌的预先计算需要一段时间,但这是一个一次性的过程,所以不是太多的问题.然而,相关的问题是,每当对mypeople执行相应的操作时,需要在mypeople表上插入/更新/删除令牌到触发表中.这可能会拖慢系统;但由于这只能在一年的几个时期内发生,也许更好的解决方案是按计划重建搜索表.
>没有干扰,所以Soundex算法只匹配完整的令牌.例如,搜索“克里斯”不会返回任何“克里斯托弗”.一个可能的解决方案是仅存储令牌的杆的Soundex,但计算杆不是一个简单的问题!这将是未来升级,可能使用TeX使用的连字引擎…

无论如何,希望有帮助:)评论欢迎!

编辑我的完整解决方案(写作和实现)现在是here,使用了Metaphone和damerau-Levenshtein距离.

原文地址:https://www.jb51.cc/mssql/80936.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐