首先,我无法提供实现代码,因为我认为它没有用,所以我会尝试详细解释到目前为止我所做的事情。
基本上,我需要开发一个类似谷歌或亚马逊的搜索栏,它将按名称向最终用户推荐产品。
搜索栏和建议面板是用纯 Java (Swing) 编写的。而数据存储在 Oracle (10g) DB 表中。由于我需要搜索 VARCHAR2
列,因此我查找了全文搜索包并找到了 Oracle Text
。使用 SQL Developer 或 SQL*Plus 时搜索速度非常快,但通过搜索栏完成搜索时速度要慢得多。
该表如下所示,大约有 220k 行,在 text
列上,我为 Oracle Text 创建了基本的 CONTEXT
索引。
CREATE TABLE inventory (
text VARCHAR2(200)
);
CREATE INDEX idx_inventory ON inventory(text) INDEXTYPE IS CTXSYS.CONTEXT;
搜索是在带有游标的数据库包中实现的,也在同一个包中我手动进行查询解析,并且运行速度也很快。由于它单独运行得非常快,我不认为问题出在包中,但我会提供一个简短的解释。
CREATE OR REPLACE PACKAGE BODY pkg_inventory
AS
FUNCTION f_parse_query(p_query IN VARCHAR2) RETURN VARCHAR2
IS
v_query VARCHAR2(32767) := '';
BEGIN
-- it always returns a parsed string with the following format
-- {foo} & {bar} & baz%
-- all the words are escaped unless for the last one, at the end of which the "%" is added
RETURN v_query;
END f_parse_query;
FUNCTION f_search(p_query IN VARCHAR2) RETURN VARCHAR2
IS
CURSOR c_inventory IS
SELECT text
FROM inventory
WHERE CONTAINS(text, v_query, 1) > 0
ORDER BY score(1) DESC;
v_query VARCHAR(32767);
v_res VARCHAR(32767);
TYPE t_result IS TABLE OF VARCHAR(32767) INDEX BY BINARY_INTEGER;
tab_res t_result;
BEGIN
v_query := f_parse_query(p_query);
OPEN c_inventory;
FETCH c_inventory BULK COLLECT INTO tab_res LIMIT 10;
CLOSE c_inventory;
-- concatenate the result in a string and return
RETURN v_res;
END f_search;
END pkg_inventory;
为了使搜索体验具有响应性,我在每次键入字符后都会重做整个过程,而真正的瓶颈是当我开始键入单词时,我需要等待几秒钟才能得到结果,因此解析的查询看起来像“b%”或“{bar} & f%”。
如何使搜索更快、响应更灵敏?
也许我可以等待用户输入至少三个字母后进行搜索。或者我可以使用编译器提示 /*+ FIRST_ROWS(10) */
但这是值得的,因为我使用 BULK COLLECT
在这种情况下我应该使用统计信息吗?
最佳答案
问题出在最后一个单词后面的通配符 %
中,这导致了我所描述的性能问题。
我通过等待用户输入至少两个字符来解决这个问题,然后我使用性能更好的模糊
运算符代替通配符。
老实说,我没有尝试过的另一个可能的解决方案是创建一个前缀索引来面对通配符 %
的问题,因为正如文档所述,它针对左截断搜索(即 bar%)进行了高度优化。
关于java - Oracle Text 优化类似 Google 搜索栏的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60623768/