使用 Oracle Text 进行全文搜索





0/5 (0投票)
如何使用 Oracle Text 进行全文搜索。
引言
您是否遇到过这样的问题:我需要找到硬盘上所有包含“Oracle”和“SQL Server”但不包含“MS Access”的文档。如果您有Oracle 10g和大约2个小时的时间,那么我可以向您展示一种使用Oracle Text轻松索引文档的方法。作为低技术方案的爱好者,您只需要一个文本编辑器和Oracle即可。我们将分三个步骤创建此解决方案
- 使用SQL*Plus创建表、索引和存储过程
- 使用VBScript导入文档
- 创建用于搜索文档的用户界面 (GUI)
Oracle部分
首先,打开SQL*Plus来创建Oracle对象。首先,我们创建一个名为my_doc的新表,其主要字段为file_name
、upload_date
和content
CREATE TABLE my_doc (
id NUMBER,
file_name VARCHAR2(255),
upload_date VARCHAR2(10),
filesize VARCHAR2(20),
mime VARCHAR2(50),
content BFILE,
CONSTRAINT doc_pk PRIMARY KEY (id)
);
字段content定义为BFILE
类型。这意味着文档的内容不会存储在Oracle中。这完全没问题,因为我们只需要索引。接下来我们将:定义一个目录,该目录将用作我们要索引的文档的根文件夹。授予用户ctxsys对此目录的读取权限。
CREATE OR REPLACE DIRECTORY documents AS 'C:\_work\datastore\';
GRANT READ ON DIRECTORY documents TO ctxsys;
接下来,我们创建一个CTXSYS.CONTEXT
类型的索引
CREATE INDEX my_doc_idx ON my_doc(content) INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('SYNC ( ON COMMIT)');
最后,我们创建存储过程put_file
CREATE OR REPLACE PROCEDURE put_file
(
p_file_name IN my_doc.file_name%TYPE,
p_upload_date IN my_doc.upload_date%TYPE,
p_filesize IN my_doc.filesize%TYPE,
p_mime IN my_doc.mime%TYPE
) AS
index_name varchar2(20) := 'my_doc_idx';
BEGIN
INSERT INTO my_doc (id, file_name, upload_date,
filesize, mime, content)
VALUES (my_doc_seq.NEXTVAL, p_file_name, p_upload_date,
p_filesize, p_mime,
BFILENAME('DOKUMENTE',p_file_name));
COMMIT;
就是这样——我们完成了Oracle对象的创建。现在我们可以使用SQL*Plus测试解决方案
exec put_file('test.doc', '10.10.2005', '100', 'doc');
执行上述语句时,请确保文件test.doc存在于已索引目录的根文件夹中。您还应使用以下语句检查表ctx_user_index_errors中的错误
SELECT err_index_name, err_timestamp,err_text FROM
ctx_user_index_errors ORDER BY err_timestamp;
如果此表中没有错误,请继续使用VBScript将更多文档插入表和索引中。要检查索引表的内容,您可以使用压缩的源文件中也包含的脚本index_stats.sql。
导入数据
接下来,我们将创建一个简单的VBScript文件以导入特定文件夹中的所有文档。首先,我们打开数据库连接并访问根目录。我们使用过程put_file
将目录中的每个文件插入到表my_doc中。最后,我们关闭数据库连接并清理所有已使用的对象。以下是VBScript文件的完整源代码
Dim strFolder: strFolder = "C:\_work\datastore\" ' index documents from this directory
' open database connection
Dim strCon: strCon = _
"Driver={Microsoft ODBC for Oracle}; CONNECTSTRING=ORCL; uid=system;pwd=man;"
Dim oCon: Set oCon = WScript.CreateObject("ADODB.Connection")
oCon.Open strCon
' insert record for each file
Dim oFs: Set oFs = WScript.CreateObject("Scripting.FileSystemObject")
Dim oFolder: Set oFolder = oFs.GetFolder(strFolder)
For Each oFile In oFolder.Files
WScript.Echo oFile.Name
Dim strCmd:
strCmd = "put_file('" & _
oFile.Name & "','" & _
Date() & "','" & _
oFile.Size & "','" & _
oFs.GetExtensionName(oFile) & "')"
oCon.Execute(strCmd)
Next
' cleanup
oCon.Close
Set oFolder = Nothing
Set oFs = Nothing
Set oCon = Nothing
这就是我们导入数据所需的一切。我尽可能简化了代码。您应该遍历目录结构以导入整个文档树。您可能还需要检查错误——读取表ctx_user_index_errors。
用户界面
正如我在引言中承诺的那样,即使是用户界面,我们也只需要记事本。因此,我们使用HTA作为文档搜索的用户界面。为此,我们创建一个名为search.hta的文件。HTA使用Internet Explorer的GUI对象,但不需要Web服务器(如IIS)即可显示。首先,我们定义头部部分
<html>
<head>
<title>Indexed files</title>
<HTA:APPLICATION
ID="objTest"
APPLICATIONNAME="HTA Test"
SCROLL="yes"
SINGLEINSTANCE="yes"
>
</head>
请访问Microsoft网站http://www.microsoft.com/technet/scriptcenter/hubs/htas.mspx,了解更多关于HTA的信息。接下来,我们需要一个脚本部分来执行搜索并在HTA页面中显示结果。
<SCRIPT LANGUAGE="VBScript">
Sub StartQuery
Dim strCon: strCon = "Driver={Microsoft ODBC for Oracle}; " & _
"CONNECTSTRING=ORCL; uid=system;pwd=man;"
Dim oCon: Set oCon = CreateObject("ADODB.Connection")
Dim oRs: Set oRs = CreateObject("ADODB.Recordset")
oCon.Open strCon
Dim strSql, strRes
strSql = "SELECT SCORE(1), file_name, filesize FROM my_doc WHERE CONTAINS(content," & _
Search.Value & ", 1) > 0 ORDER BY SCORE(1) DESC"
strRes = "<table border=1 cellpadding=10 cellspacing=0><tr><th>found" & _
"</th><th>title</th><th>size</th><th>action</th></tr>"
Set oRs = oCon.Execute(strSql)
While Not oRs.EOF
strRes = strRes & "<tr><td>" & _
oRs.Fields(0).Value & "</td><td>" & _
oRs.Fields(1).Value & "</td><td>" & _
oRs.Fields(2).Value & "</td><td><a href='datastore/" & _
oRs.Fields(1).Value & "' target=_blank>Open in new windows</a>" & _
"</td></tr>"
oRs.MoveNext
Wend
oCon.Close
strRes = strRes & "</table>"
DataArea.InnerHtml = strRes
Set oCon = Nothing
End Sub
</SCRIPT>
以下是上述代码中的一些要点
strSql = "SELECT SCORE(1), file_name, filesize FROM my_doc " & _
WHERE CONTAINS(content," & Search.Value & ", 1) > 0 " & _
ORDER BY SCORE(1) DESC"
这是一个对文件内容执行全文搜索的查询。例如:where
条件CONTAINS(content, 'Perl', 1)
仅选择包含字符串Perl的文档,并获取文档中匹配项的数量。变量Search.Value
是稍后在HTA的主体部分定义的文本框的值。
DataArea.InnerHtml = strRes
使用HTML表格格式化结果后,我们将表格分配给'DataArea.InnerHtml
'。对象DataArea
也在HTA的主体部分定义。在这里,我们看到主体部分(我删除了一些格式化代码,如表格和图片),以简化内容
<body>
<input type="text" name="Search" size="60">
<input type="button" value="Start Query"
name="startQuery" onClick="StartQuery"><p>
<p>
<span id = "DataArea"></span>
</body>
在主体部分,我们定义一个名为Search
的文本区域。Search.Value
的内容作为Select
语句的输入。接下来,我们定义一个标题为“开始查询”的按钮,其事件处理程序调用脚本部分中定义的子例程StartQuery
。最后,我们需要一个DataArea
。我们将查询的格式化输出分配给'DataArea.InnerHtml
'。
现在我们完成了——您可以通过双击资源管理器启动搜索界面。请参阅GUI中有效搜索的一些示例。有关文档搜索的更多信息,请查看:http://oraclesvca2.oracle.com/docs/cd/B13789_01/text.101/b10729/toc.htm。
关注点
如您所见,使用Oracle Text为您的Office文档创建索引非常简单。但是在此解决方案中,我们只有文档内容的快照。如果您更改了文档会发生什么?该文档的索引将不再有效。因此,当文档发生更改时,我们应该注意更新索引。我已经有了一个解决这个问题的想法。