Oracle Text 为 Google 之类的搜索栏优化查询
Oracle Text optimize query for a Google like search bar
首先我无法提供实现代码,因为我认为它没有用,所以我会尝试详细解释我到目前为止所做的事情。
基本上我需要开发一个 Google 或类似亚马逊的搜索栏,它会按名称向最终用户推荐产品。
搜索栏和建议面板是用普通 Java (Swing) 编写的。而数据存储在 Oracle (10g) DB table 中。因为我需要搜索 VARCHAR2
列,所以我查找了全文搜索包并找到了 Oracle Text
。使用 SQL 开发人员或 SQL*Plus 时搜索速度超快,但通过搜索栏完成搜索时速度要慢得多。
table 如下所示,它有大约 220k 行,在 text
列上,我为 Oracle Text 创建了一个基本的 CONTEXT
索引。
CREATE TABLE inventory (
text VARCHAR2(200)
);
CREATE INDEX idx_inventory ON inventory(text) INDEXTYPE IS CTXSYS.CONTEXT;
搜索是在带有游标的 DB 包中实现的,也在同一个包中我手动进行查询解析,而且速度也很快。由于它单独运行非常快,我认为问题不在包中,但我会提供一个简短的解释。
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
并且在这种情况下我应该使用统计信息吗?
问题出在最后一个词后面的通配符 %
中,这导致了我描述的性能问题。
我通过等待用户输入至少两个字符来解决它,然后我使用性能更好的 fuzzy
运算符代替通配符。
老实说,我没有尝试过的另一种可能的解决方案是创建一个前缀索引来解决通配符问题 %
,因为它针对左截断搜索(即 bar%)进行了高度优化正如文件所说。
首先我无法提供实现代码,因为我认为它没有用,所以我会尝试详细解释我到目前为止所做的事情。
基本上我需要开发一个 Google 或类似亚马逊的搜索栏,它会按名称向最终用户推荐产品。
搜索栏和建议面板是用普通 Java (Swing) 编写的。而数据存储在 Oracle (10g) DB table 中。因为我需要搜索 VARCHAR2
列,所以我查找了全文搜索包并找到了 Oracle Text
。使用 SQL 开发人员或 SQL*Plus 时搜索速度超快,但通过搜索栏完成搜索时速度要慢得多。
table 如下所示,它有大约 220k 行,在 text
列上,我为 Oracle Text 创建了一个基本的 CONTEXT
索引。
CREATE TABLE inventory (
text VARCHAR2(200)
);
CREATE INDEX idx_inventory ON inventory(text) INDEXTYPE IS CTXSYS.CONTEXT;
搜索是在带有游标的 DB 包中实现的,也在同一个包中我手动进行查询解析,而且速度也很快。由于它单独运行非常快,我认为问题不在包中,但我会提供一个简短的解释。
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
并且在这种情况下我应该使用统计信息吗?
问题出在最后一个词后面的通配符 %
中,这导致了我描述的性能问题。
我通过等待用户输入至少两个字符来解决它,然后我使用性能更好的 fuzzy
运算符代替通配符。
老实说,我没有尝试过的另一种可能的解决方案是创建一个前缀索引来解决通配符问题 %
,因为它针对左截断搜索(即 bar%)进行了高度优化正如文件所说。