【发布时间】:2011-11-28 14:16:40
【问题描述】:
我有一个 Oracle 数据库,与许多数据库一样,它有一个包含传记信息的表。对此,我想以“自然”的方式按名称搜索。
该表有 forename 和 surname 字段,目前,我使用的是这样的:
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,
forename,
surname
from mytable
where contains(forename,'!%john%',1) > 0
and contains(surname,'!%smith%',2) > 0
order by relevance desc;
这具有使用 Soundex 算法以及全文索引的优点,因此它应该更高效一些。 (虽然,我的轶事结果表明它非常缓慢!)对此我唯一的担忧是:
首先,需要以某种有意义的方式刷新文本索引。使用
on commit会太慢,并且可能会干扰前端软件(我无法控制)与数据库的交互方式;所以需要考虑...Oracle 返回的结果不是很自然地排序的;我不太确定这个
score函数。例如,我的开发数据显示“Jonathan Peter Jason Smith”在顶部——很好——但“Jane Margaret Simpson”与“John Terrance Smith”处于同一级别
我认为删除前面的通配符可能会在不降低结果的情况下提高性能,因为在现实生活中,您永远不会在名称中间搜索块。但是,否则,我对想法持开放态度……这种情况一定是实施得令人作呕!任何人都可以就我现在正在做/考虑的事情提出更好的方法吗?
谢谢:)
【问题讨论】:
-
您还可以考虑将 Lucene 用于非 Oracle 模糊搜索引擎(并且它是免费的)。但取决于您的环境和需求(和技能)
-
与其说是答案,不如说是建议。我使用 MySQL 和全文搜索来搜索帐户详细信息 - 基于名字和姓氏。我还遇到了基于分数的不相关结果,直到我创建了一个新列“full_name”,其中包含名字和姓氏一起(反规范化),然后改为搜索该列 - 我的结果更精确,返回速度更快。我还使用了布尔模式,所以它匹配两个名字“john”和“smith”。如果我没有使用布尔模式,它会返回“john”或“smith”的结果,这是错误的
-
您可以更改数据库架构吗?
-
@MartinG 是的,我正在考虑连接这些字段。我不知道是否可以在不更改架构的情况下做到这一点(即,使用 CONTAINS 函数中的两列)...
-
...@X-Zero,对于表格列,我做不到;但我认为添加索引没有问题。
标签: sql oracle full-text-search soundex oracle-text