Oracle?數(shù)據(jù)庫中的全文搜索整體流程分析
0. 引言
這篇文章會介紹 Oracle Text 索引,旨在引導您了解創(chuàng)建文本索引、執(zhí)行文本查詢和維護文本索引的基礎知識。
Oracle Text 為 Oracle 數(shù)據(jù)庫提供全文索引功能,允許您通過指定內(nèi)容中的單詞、短語或其他文本模式來搜索文本內(nèi)容(例如 VARCHAR2 或 CLOB 數(shù)據(jù))。
Oracle Text 是數(shù)據(jù)庫的標準組件,允許您在 Oracle 數(shù)據(jù)庫中的文本數(shù)據(jù)中進行快速全文搜索。例如,它可以讓您在地址字段中查找拼寫錯誤的單詞,或者獲取包含特定短語的 Microsoft Word 文檔列表。
雖然表面上它類似于 LIKE 運算符的索引版本,但存在許多差異。
Oracle Text 對數(shù)據(jù)庫中的文本內(nèi)容創(chuàng)建基于單詞(word-based)的索引。該內(nèi)容的范圍可以從 VARCHAR2 列中的幾個單詞到存儲在 BLOB 列中的多章節(jié) PDF 文檔(甚至存儲在文件系統(tǒng)外部、URL 或云存儲上)。
這篇文章主要面向開發(fā)人員和 DBA,內(nèi)容涵蓋創(chuàng)建索引、基本搜索功能和索引維護。
1. 整體流程
整體流程如下,
我們將創(chuàng)建一個名為“user_data”的簡單表,其中包含客戶信息。其中包括記錄 ID 的數(shù)字列、客戶名稱的 VARCHAR2 列、訂單金額的數(shù)字列以及銷售代表所做的任何注釋的 VARCHAR2 列。
我們將填充該表,然后在注釋列上創(chuàng)建一個文本索引。
然后,我們將使用 Oracle Text CONTAINS 運算符完成各種類型的查詢。我們還將在注釋列上顯示一些帶有全文搜索的混合查詢,并在其他關(guān)系列上顯示附加過濾器。
接下來,我們將了解如何同步和優(yōu)化 Oracle Text 索引。
最后,我們將了解如何在對象存儲上索引二進制文件,例如 Microsoft Word 或 PDF 文件。
2. 創(chuàng)建索引
2-1. 創(chuàng)建一個簡單的表
我們將創(chuàng)建一個簡單的表來保存模擬用戶銷售記錄。它包含一個用于記錄 ID 的數(shù)字列、一個用于客戶名稱的 varchar 列、另一個用于銷售額的數(shù)字列以及另一個用于注釋的 varchar 列。將以下內(nèi)容復制到“工作表”區(qū)域,然后按“運行語句”按鈕:
create table user_data (id number, name varchar2(100), amount number(17,2), note varchar2(2000) )
插入幾行數(shù)據(jù),
insert into user_data select 1, 'John Smith', 123.45, 'First order from John Smith.' from dual union select 2, 'Mary Poppins', 67.89, 'First ever order from Marie Poppins.' from dual union select 3, 'John Smith', 99.45, 'Second order from Johnny Smith.' from dual commit;
檢查表中是否有數(shù)據(jù),
select * from user_data
2-2. 創(chuàng)建文本索引
文本索引是域索引(domain index)的一個示例。域索引是特定類型數(shù)據(jù)(或“域”)的專門索引。為了告訴內(nèi)核要創(chuàng)建什么類型的索引,我們使用特殊語法“INDEXTYPE IS …”。最常見的文本索引類型,也是我們在這里使用的,是 CONTEXT 索引類型。
復制并運行以下 SQL,這將在表的 TEXT 列上創(chuàng)建索引。
create index myindex on user_data(note) indextype is ctxsys.context
檢查數(shù)據(jù)庫視圖中的索引,
select index_name, index_type, status from user_indexes where index_name = 'MYINDEX'
這樣就有了您的索引,index_type 為“DOMAIN”,狀態(tài)為“VALID”。文本索引必須有效才能使用。在大型表上創(chuàng)建的索引可能會顯示為 INPROGRS,這意味著索引創(chuàng)建正在進行中,但尚未準備好使用。
我們還可以在“文本數(shù)據(jù)字典”中查找。這是用戶 CTXSYS 擁有的一組視圖,專門用于 Oracle Text 索引。這些視圖均以“CTX_”為前綴,所有用戶都可以查看。運行以下命令:
select idx_name, idx_table, idx_text_name from ctx_user_indexes
這告訴我們索引 MYINDEX 是在表 USER_DATA 的“NOTE”列上創(chuàng)建的。
2-3. 查看創(chuàng)建的基礎表
文本索引作為一組基礎表來實現(xiàn)。它們通常采用 DR < i n d e x n a m e > <indexname> <indexname> 形式,其中后綴表示表的特定類型。通常不需要知道這些索引中有什么,但其中一個(“dollar I”表)特別有趣。
注意:子表列表將隨數(shù)據(jù)庫版本和所選索引選項的不同而變化。您可能會看到與此處顯示的列表不同的列表。
您應該看到列出了幾個表。單擊旁邊的三角形,打開 DR M Y I N D E X MYINDEX MYINDEXI 的表定義。
我們看到一個列列表。我們主要感興趣的是 TOKEN_TEXT。
我們之前討論了 Oracle Text 如何使用“基于單詞”的索引。更準確地說,它使用“基于令牌”的索引,因為令牌不一定是單詞(盡管通常是)。 “$I”表包含所有索引標記的列表,我們可以使用以下查詢查看它們:
select token_text from dr$myindex$i
注意到列表中的任何內(nèi)容了嗎?文本中并未出現(xiàn)所有單詞 - 缺少“from”。這是因為它被指定為“停用詞” - 在搜索中不是很有用的常見詞,但可能會占用索引中的大量空間。默認情況下,我們不會對它們建立索引 - 盡管使用高級選項,我們可以告訴系統(tǒng)對所有單詞建立索引,或者提供我們不想索引的單詞的“自定義非索引字表”。默認的停用詞列表將隨語言的不同而變化,并且取決于數(shù)據(jù)庫的默認語言設置(自治數(shù)據(jù)庫始終為英語)。您可以按照此處的示例自定義停用詞列表:創(chuàng)建停用詞列表和添加停用詞。
目前我們不需要了解任何有關(guān)底層索引表的信息。但查看已索引的單詞很有用,并且在嘗試找出特定查詢?yōu)楹稳绱诉\行時,有時值得參考此列表(下一步將介紹查詢)。
3. 運行查詢
我們將探討用于查詢 Oracle Text 索引的 CONTAINS 運算符。
在這個章節(jié),您將:
- 探索 CONTAINS 文本查詢運算符
- 查看各種基本文本搜索
- 了解 SCORE() 運算符如何幫助您對查詢結(jié)果進行排名
3-1. 運行文本查詢
首先熟悉 USER_DATA 中包含的文本。
select * from user_data
3-2. CONTAINS 運算符
要搜索 Oracle Text CONTEXT 索引,必須使用 CONTAINS 運算符。 CONTAINS 特定于該類型的索引。與“普通”索引不同,無論有沒有索引,您都無法獲得相同的結(jié)果。如果不存在 CONTEXT 索引,CONTAINS 根本不起作用。
CONTAINS 是一個返回數(shù)字的函數(shù)。它幾乎總是以 WHERE CONTAINS(…) > 0 的形式使用。如果返回值大于零,則該行有匹配項,如果為零則沒有匹配項。
CONTAINS 需要兩個或三個參數(shù)。第三個是可選的,我們稍后再討論。兩個必需的參數(shù)是:
- 要搜索的列的名稱
- 要搜索的字符串值。該字符串可以是文字字符串,也可以是任何計算結(jié)果為字符串的字符串(VARCHAR2 或 CLOB)。
讓我們嘗試一個簡單的例子。我們將查找單詞“John”:
select * from user_data where contains ( note, 'john' ) > 0
請注意,我們找到了包含單詞“John”的一行。但是,我們沒有找到包含“Johnny”的行。這說明了 Oracle Text 搜索與簡單的 LIKE 搜索(例如 WHERE TEXT LIKE ‘%John%’)之間的眾多差異之一。 LIKE 執(zhí)行子字符串搜索,而 CONTAINS 則(默認情況下)查找整個單詞。
您還可以嘗試搜索大寫的 JOHN。你會得到相同的結(jié)果。與 LIKE 搜索不同,CONTAINS 搜索(至少對于英文索引)不區(qū)分大小寫。
3-3. 混合查詢
CONTAINS 是一個 SQL 運算符。當然,您可以將其與任何其他 WHERE 子句結(jié)合起來。例如,我們可以查找 AMOUNT 值小于 100 的單詞“Smith”。讓我們嘗試一下:
select * from user_data where amount < 100 and contains ( note, 'smith' ) > 0
3-4. OR 查詢
CONTAINS 的搜索字符串參數(shù)有自己的語法,具有各種內(nèi)部運算符,例如 AND、OR、NEAR 等。我們在這里僅展示一個示例,有關(guān)更多信息,您應該參閱文檔。
之前,我們搜索“John”但沒有找到“Johnny”。讓我們搜索一下:
select * from user_data where contains ( note, 'john OR johnny' ) > 0
果然,現(xiàn)在我們兩者都找到了。
3-5. 通配符
運行先前搜索的另一種方法是使用通配符 %。與標準 SQL 一樣,百分號 % 匹配任何字符串,下劃線 _ 字符匹配任何單個字符。
因此 john% 將匹配“john”、“johnny”、“johnnie”、“johnston”等。 l_se 將匹配“lose”,但不匹配“loose”。
由于通配符僅適用于索引單詞,因此它們永遠不會匹配空格。因此 qui%step 將匹配“quickstep”,但不會匹配短語“quick step”。
我們來嘗試一下:
select * from user_data where contains ( note, 'john%' ) > 0
3-6. 短語搜索
如果您想在同一文檔中查找兩個單詞,您可以執(zhí)行 AND 搜索,類似于上面的 OR 搜索。如果您想一起查找兩個單詞,只需將它們作為短語輸入即可。無需添加引號或任何內(nèi)容,兩個單詞一起自動構(gòu)成短語搜索,并且僅當它們一起出現(xiàn)在索引文本中時才會匹配。
select * from user_data where contains ( note, 'first order' ) > 0
Note that only matches the first row where the actual phrase “first order” appears, and not the other row where the two words appear, but not as a phrase.
3-7. 模糊搜索(Fuzzy searches)
如果您犯了錯誤或根本不記得確切的拼寫,您可以進行模糊搜索。它不僅會找到原始搜索詞,還會找到所有與其相似的搜索詞。
select * from user_data where contains ( note, 'fuzzy(popins)' ) > 0
請注意,搜索詞“popins”存在拼寫錯誤。但通過模糊搜索,它實際上找到了包含正確單詞“Poppins”的結(jié)果。
3-8. 附近的搜索
您可以使用 NEAR 運算符查找彼此接近的單詞。它將查找彼此指定距離內(nèi)的單詞。例如,以下查詢未找到任何結(jié)果。因為“order”和“smith”之間有兩個單詞,但我們指定它們之間最多有 1 個單詞。
select * from user_data where contains ( note, 'near((order, smith), 1)' ) > 0
下一個查詢找到結(jié)果,因為它正確指定了“order”和“smith”之間的距離 2。
select * from user_data where contains ( note, 'near((order, smith), 2)' ) > 0
請注意,默認情況下,近運算符中的單詞順序并不重要,除非 ORDER 參數(shù)顯式設置為 TRUE。但在短語搜索中,單詞的順序確實很重要。
You can find a list of query operators here: Contains Query Operators.
4. 維護索引
到目前為止,我們已經(jīng)了解了如何創(chuàng)建和查詢 Oracle Text 索引。這是 Oracle Text 的基礎知識,但我們需要討論索引維護下的幾個主題。
默認情況下,Oracle Text 索引不是事務性的。索引表發(fā)生更改后,必須先同步索引,然后才能通過搜索找到新數(shù)據(jù)。
對 Oracle Text 索引進行多次更改后,由于索引碎片和垃圾(已刪除)數(shù)據(jù)在索引中累積,其性能將達不到理想狀態(tài)。為了讓索引達到最佳狀態(tài),我們必須對其進行優(yōu)化。
在本章節(jié)中,您將:
- 看到索引沒有自動更新
- 了解如何手動或自動同步索引
- 看到索引隨著時間的推移變得碎片化
- 了解如何優(yōu)化索引
4-1. 同步
讓我們向 USER_DATA 中插入一個新行。復制以下內(nèi)容并單擊“運行語句”按鈕:
insert into user_data values (4, 'Mike Smith', 98.76, 'Third one from Mike Smith.'); commit;
現(xiàn)在嘗試查詢剛剛插入的數(shù)據(jù):
select * from user_data where contains ( note, 'mike' ) > 0
當你運行它時,你將不會得到任何結(jié)果。請記住 CONTAINS 僅適用于 CONTEXT 索引。如果該索引不是最新的,那么結(jié)果也不會是最新的。為了獲得正確的結(jié)果,我們必須同步索引。執(zhí)行此操作的基本方法是調(diào)用 PL/SQL 過程 CTX_DDL.SYNC_INDEX(您的用戶需要具有 CTXAPP 角色才能訪問該過程,或者已被顯式授予 EXECUTE ON CTXSYS.CTX_DDL)。索引名稱作為參數(shù)傳遞給過程。
運行這個命令同步索引,
execute ctx_ddl.sync_index ('myindex')
現(xiàn)在再次嘗試之前的“mike”查詢,它將起作用。
4-2. 提交時自動同步
手動運行 SYNC_INDEX 非常高效,并且可以讓您完全控制。但是,您可以讓索引自動同步,方法是指定應在提交時同步,或者指定定期的時間段(例如每分鐘)來執(zhí)行同步。
首先刪除當前索引:
drop index myindex
每當需要非默認索引行為時,我們都會對索引使用 PARAMETERS 子句。這里我們將指定 SYNC(ON COMMIT) 以使其在 COMMIT 時自動同步:
create index myindex on user_data(note) indextype is ctxsys.context parameters ('sync (on commit)')
現(xiàn)在我們將向表中添加一個新行并搜索它:
insert into user_data values (5, 'Peter Williams', 110.68, 'Canceled order from Peter Williams.' ); commit;
我們將找到新行,而無需調(diào)用 CTX_DDL.SYNC_INDEX。
select * from user_data where contains ( note, 'williams' ) > 0
4-3. 按時間間隔自動同步
SYNC(ON COMMIT) 很方便,但在高事務率情況下并不理想。它可能會導致事務在等待上一個 SYNC 完成時被延遲。相反,您可以選擇在特定時間段執(zhí)行 SYNC。
該時間段越長(通常選擇五分鐘),您的索引需要優(yōu)化的次數(shù)就越少。但是,如果您需要近乎實時的同步,則可以選擇低至一秒的時間段。
時間間隔SYNC使用數(shù)據(jù)庫調(diào)度程序,因此在19c及之前您必須具有CREATE JOB權(quán)限才能使用它。
刪除現(xiàn)有索引:
drop index myindex
現(xiàn)在再次創(chuàng)建索引,但這次指定應每分鐘同步一次。時間段的語法來自 DBMS_SCHEDULER。
create index myindex on user_data(note) indextype is ctxsys.context parameters ('sync (every "freq=minutely; interval=1")')
現(xiàn)在插入一個新行
insert into user_data values (6, 'Paul Williams', 77.36, 'Returned order from Paul Williams.' ); commit;
搜索新行。最初,您可能會發(fā)現(xiàn)它找不到新行,但繼續(xù)重復查詢,它會在一分鐘內(nèi)起作用。
select * from user_data where contains (note, 'paul') > 0;
4-4. 優(yōu)化
檢查“$I”表,現(xiàn)在我們已經(jīng)完成了索引的更新,讓我們再看一下 $I 表中的索引詞列表。運行以下命令:
select token_text from dr$myindex$i
您應該看到現(xiàn)在有兩個單詞“order”和“williams”的條目。我們不會擔心到底為什么(盡管請注意它們是在上次更新中使用的),但我們只是說這是索引碎片的一個示例。
優(yōu)化索引,我們可以使用 ctx_ddl 包中的另一個 PL/SQL 命令來優(yōu)化索引:ctx_ddl.optimize_index。這需要兩個強制參數(shù):索引名稱和要執(zhí)行的優(yōu)化類型。常見值為“FULL”或“REBUILD”。我們將選擇“FULL”:
execute ctx_ddl.optimize_index('myindex', 'FULL')
現(xiàn)在再次嘗試從 $I 表中進行先前的選擇?,F(xiàn)在只有一個“order”條目和一個“williams”條目 - 這些單詞的索引信息已被壓縮為每個單詞的一行。
您現(xiàn)在應該在創(chuàng)建 Oracle Text 索引、針對這些索引運行基本查詢以及維護這些索引方面具備良好的基礎。
5. 對象存儲上的索引文件
在之前的實驗中,我們向您展示了如何對簡單的 VARCHAR2 文本進行索引。但 Oracle Text 的能力遠不止于此。例如,它可以自動識別和處理大約 150 種不同的二進制文件格式。有 PDF 文檔嗎?沒問題。想要索引 Powerpoint 演示文稿中的所有文本嗎?當然可以,為什么不呢?
Oracle Text 可以處理文件系統(tǒng)或 URL 上保存的文件,但對于本例,我們將把文件直接加載到數(shù)據(jù)庫的 BLOB(二進制長對象)列中。
完成之前的所有實驗后,此實驗是可選的。您可以索引自己的文件,或使用我們提供的簡單的 Microsoft Word 文件。
在本章節(jié)中,您將:
- 將文件復制到對象存儲
- 創(chuàng)建“預授權(quán)請求”URL 來訪問這些文件
- 使用 DBMS_CLOUD.GET_OBJECT 將文件加載到數(shù)據(jù)庫中
- 創(chuàng)建一個首選項,告訴 Text 使用 AUTO_FILTER
索引文件并使用內(nèi)容詞進行搜索
5-1. 將文件加載到對象存儲
轉(zhuǎn)到 Oracle Cloud 中的主菜單(請注意,這與數(shù)據(jù)庫操作的菜單不同 - 它可能在不同的選項卡中打開)。
打開“漢堡包”菜單,然后選擇“存儲”,然后選擇“對象存儲和歸檔存儲”下的存儲桶。
在“存儲桶”頁面中,從“搜索分區(qū)”框中選擇您的根分區(qū)。
然后點擊“創(chuàng)建存儲桶”,您可以提供名稱或僅保留默認名稱。單擊創(chuàng)建。
現(xiàn)在單擊新創(chuàng)建的存儲桶。
滾動到頁面底部找到對象并單擊上傳。
在“上傳對象”面板中,您可以使用文件選擇器從計算機中選擇某些 Office 或 PDF 文件,或?qū)⑺鼈兺戏诺巾撁嫔稀?/p>
如果您沒有任何合適的文件,您可以從這里下載一個簡單的 Microsoft Word 文檔。
關(guān)于 PDF 文件的說明:Oracle Text 無法處理純圖像的 PDF 文件(即使它們是文本圖像 - 我們沒有 OCR 功能)。 PDF 文件必須嵌入文本。有時,PDF 文件會受到文本訪問保護,或使用無法讀取的特殊“位圖”字體。不過,絕大多數(shù) PDF 文件都可以使用。
選擇文件后,單擊“上傳”按鈕即可完成。然后單擊“關(guān)閉”,您應該會看到存儲桶中列出了您的文件。
為文件創(chuàng)建預驗證請求 (PAR)。
對于存儲桶中的每個文件,我們需要創(chuàng)建一個“預驗證請求”。這是一個特殊的 URL,其中包含文件的嵌入式訪問密鑰。這意味著任何有權(quán)訪問該 URL 的人都可以訪問該文件,但實際上不可能猜測該 URL。
單擊文件右側(cè)的“三點”菜單,然后選擇“創(chuàng)建預驗證請求”。
在彈出的面板上,選擇“對象”,然后單擊“創(chuàng)建預驗證請求”按鈕。
您將看到一個“預驗證請求詳細信息”面板,單擊“復制”按鈕復制 URL,然后將其保存到文本文件以供以后使用。對每個要索引的文件重復此操作。
注意:不要擔心可怕的“不會再顯示”。您可以隨時創(chuàng)建另一個 PAR。
5-2. 將文件加載到數(shù)據(jù)庫中
在瀏覽器中打開“數(shù)據(jù)庫操作”選項卡(或者如果需要,可以使用之前的說明重新打開它)并轉(zhuǎn)到 SQL。
創(chuàng)建一個表來保存文件數(shù)據(jù)。運行以下語句:
create table documents (name varchar2(50), content blob)
將文件從對象存儲加載到表中。
對您存儲的每個文件運行一次,替換為 PAR URL(您在上一步中保存的)和短名稱或描述。不要忘記為每個文件指定不同的名稱/描述。
declare body blob; begin body := dbms_cloud.get_object(null, 'https://objectstorage.uk...HelloWorld.docx'); insert into documents values ('Hello World as an MS Word file', body); end;
通過獲取名稱和 LOB 列的大小來檢查文件是否已正確加載
select name, dbms_lob.getlength(content) from documents
5-3. 索引文檔
創(chuàng)建過濾器首選項。
Oracle Text 很聰明地發(fā)現(xiàn),如果它對 BLOB 列建立索引,那么它顯然是在處理二進制文件,需要通過 AUTO_FILTER 才能被識別并轉(zhuǎn)換為文本。所以實際上我們可以像以前一樣創(chuàng)建一個簡單的文本索引。但為了說明如何自定義索引選項,我們將向您展示如何創(chuàng)建一個首選項,明確告訴文本使用 AUTO_FILTER,覆蓋其索引的數(shù)據(jù)類型的任何默認值。我們還將根據(jù)我們的偏好設置一個 TIMEOUT 屬性,告訴它過濾任何特定文件的時間不要超過 10 秒。
我們需要創(chuàng)建一個首選項,然后設置該首選項的屬性。這些都是使用名為 ctx_ddl 的包完成的,任何具有 CTXAPP 角色的用戶都可以執(zhí)行該包。由于這里有兩個語句,因此使用“運行腳本”按鈕運行它們是最簡單的?;蛘?,突出顯示這兩個語句并按“運行”。
exec ctx_ddl.create_preference ('my_filter_pref', 'AUTO_FILTER') exec ctx_ddl.set_attribute ('my_filter_pref', 'TIMEOUT', 10)
(如果您需要再次運行該程序,您可以調(diào)用 ctx_ddl.drop_preference,僅將首選項名稱作為參數(shù))
使用我們的過濾器首選項創(chuàng)建索引。
對于任何具有非標準選項的索引,我們使用 PARAMETERS 子句(我們之前在 SYNC 選項中看到過它)。該子句采用單個字符串,該字符串主要是首選項類型和首選項名稱的列表。在這里,我們的首選項類型是“filter”,首選項名稱是“my_filter_pref”。如果我們想添加更多文件,我們還將包括同步(提交時)。
create index documents_index on documents(content) indextype is ctxsys.context parameters ('filter my_filter_pref sync(on commit)')
如果該語句出現(xiàn)任何問題 - 就像您拼寫錯誤您的偏好一樣,它可能會創(chuàng)建失敗的索引。在創(chuàng)建新索引之前,您需要刪除該索引。
5-4. 搜索文件
我們的 CONTAINS 將針對索引的 CONTENT 列運行,但由于它是二進制的,因此沒有必要選擇它,因此我們只需選擇 NAME 列。如果您不為 HelloWorld 文檔編制索引,則可以在此處替換為您自己的搜索字符串。
select name from documents where contains (content, 'world') > 0
可選:獲取片段(上下文中突出顯示的搜索詞)
我們無法讀取表中的二進制文檔,但我們可以讓 Text 用它來做一些事情。 CTX_DOC 包有各種處理索引文檔的過程。讓我們看一下 CTX_DOC.SNIPPET,它獲取搜索詞周圍的文檔塊。它通常從 PL/SQL 調(diào)用,但如果我們傳入索引名稱和我們正在查看的行的 ROWID 值,我們也可以從 SQL SELECT 查詢調(diào)用它。我們還必須告訴它所使用的搜索詞。所以我們得到:
select name, ctx_doc.snippet('DOCUMENTS_INDEX', rowid, 'world') from documents where contains (content, 'world') > 0
如果您正在搜索其他文檔,請不要忘記將“world”更改兩次。
CTX_DOC包含許多用于處理單個文檔的函數(shù)。值得一看文檔。
如果您已完成此可選模塊,您就會知道 Oracle Text 可以處理的不僅僅是數(shù)據(jù)庫中的短文本。為什么不嘗試更多的文件呢?也許將“文檔”文件夾中的所有文件加載到數(shù)據(jù)庫中,最終,您將能夠找到您多年前編寫的難以捉摸的 Powerpoint,但不記得它的文件名。
6. (可選)情感分析
情緒分析可以回答“產(chǎn)品評論是正面還是負面?”等問題?;?ldquo;客戶滿意還是不滿意?”例如,從包含特定產(chǎn)品的多個評論的文檔集中,您可以確定表明該產(chǎn)品是好還是壞的總體情緒。
Oracle Text 使用戶能夠使用經(jīng)過訓練以識別情感元數(shù)據(jù)的情感分類器對主題或文檔執(zhí)行情感分析。
Oracle Text 可以使用基本的內(nèi)置“詞袋”分類器(針對英文文本)執(zhí)行情感分析。為了獲得更好的結(jié)果或使用其他語言,您可以使用一組培訓文檔來訓練您自己的分類器。
本章節(jié)將使用Oracle數(shù)據(jù)庫創(chuàng)建一個分類器,并用它來分析一組有關(guān)相機評論的文檔的情緒。
在本章節(jié)中,您將:
- 使用內(nèi)置的默認分類器分析文檔的情緒
- 使用單獨的訓練文檔集訓練自定義分類器
- 使用經(jīng)過訓練的分類器來分析文檔
- 比較兩種分析方法的準確性
6-1. 使用默認分類器
加載評論數(shù)據(jù)進行分析,這是您要分析的實際數(shù)據(jù)。在本例中,我們將創(chuàng)建一個“camera_review”表并將評論文本加載到該表中。
create table camera_reviews(review_id number primary key, review_text varchar2(2000))
插入評論數(shù)據(jù)。您需要在運行之前選擇所有行,或者使用“運行 SQL 腳本”按鈕,
insert into camera_reviews values (1, 'this camera is OK'); insert into camera_reviews values (2, 'the camera is absolutely fantastic'); insert into camera_reviews values (3, 'the camera is terrible'); insert into camera_reviews values (4, 'another fantastic camera from Nikon'); insert into camera_reviews values (5, 'What a terrible camera from Canon'); insert into camera_reviews values (6, 'camera is not too bad, but ok for the price'); insert into camera_reviews values (7, 'lens is not too bad, love the looks of this camera'); insert into camera_reviews values (8, 'the Sony camera has a lot of new features, although a bit pricey');
檢查所有行是否已加載。您應該看到 8 行。
exec ctx_ddl.create_preference('review_lexer', 'AUTO_LEXER')
使用我們剛剛創(chuàng)建的首選項和 NOPOPULATE 關(guān)鍵字創(chuàng)建評論數(shù)據(jù)的索引,
create index camera_revidx on camera_reviews(review_text) indextype is ctxsys.context parameters ('lexer review_lexer NOPOPULATE');
6-2. 運行情緒分析
情緒分析使用 PL/SQL 過程 CTX_DOC.SENTIMENT_AGGREGATE 逐行運行。返回一個數(shù)值,表示文檔的情緒,范圍在 -100 到 100 之間,其中 -100 最大為負面,0 為中性,100 最大為正面。該函數(shù)采用索引的名稱和 TEXTKEY,TEXTKEY 可以是行的唯一鍵值,或者如果表沒有唯一鍵,則為 ROWID 值(我們可以使用 CTX_DOC.SET_KEY_TYPE 在使用鍵和 rowids 之間進行交換。
因此,為了獲取每個評論文本及其計算出的情緒,我們可以運行以下命令:
select ctx_doc.sentiment_aggregate( index_name => 'camera_revidx', textkey => review_id ) sentiment, review_text from camera_reviews;
6-3. 使用經(jīng)過訓練的分類器
訓練分類器涉及提供一組已知為正面、中性或負面的訓練文檔。此類文檔可能已經(jīng)過人工審核,或者您可能會使用用戶提供的其他元數(shù)據(jù)(例如星級評定)。
訓練使用稱為支持向量機(SVM)的機器學習算法。
您提供的訓練文檔越多,分類器就越好。由于我們在這里只提供很少的示例文檔,因此分類器將非常粗糙。
加載訓練數(shù)據(jù),我們將加載評論培訓表。在下一步中,我們將為每條評論貼上相關(guān)情緒的標簽。
首先,創(chuàng)建一個名為“training_camera”的表來保存訓練數(shù)據(jù),
create table training_camera(train_id number primary key, train_text varchar2(2000))
將訓練數(shù)據(jù)插入訓練表,
insert into training_camera values( 1,'this camera is OK'); insert into training_camera values( 2,'the camera is absolutely fantastic'); insert into training_camera values( 3,'the camera is terrible'); insert into training_camera values( 4,'i love the lens, but overall ok camera'); insert into training_camera values( 5,'the camera has mediocre lens, but a lot of nice features'); commit;
用情感標記訓練數(shù)據(jù),我們使用一個單獨的表來保存與“training_camera”表中每一行相關(guān)的情緒:
create table training_category(doc_id number, category number, category_desc varchar2(100))
對于訓練數(shù)據(jù)表中的每一行,我們必須插入一行來指示該行的類別。類別是代表中性、正面或負面的整數(shù)值,如下表所列。 “categoy_desc”列作為人類可讀的注釋包含在此處,在分類過程中既不是必需的,也不是使用的。
整數(shù) | 意義 |
---|---|
0 | 中立 |
1 | 積極 |
2 | 負 |
鑒于此,我們可以如下創(chuàng)建類別行(您可能希望返回訓練表以檢查每行涉及的文本)
insert into training_category values( 1, 0, ‘neutral’);
insert into training_category values( 2, 1, ‘positive’);
insert into training_category values( 3, 2, ‘negative’);
insert into training_category values( 4, 0, ‘neutral’);
insert into training_category values( 5, 0, ‘neutral’);
6-4. 創(chuàng)建 SVM 情感分類器
exec ctx_ddl.create_preference('classifier_camera','SENTIMENT_CLASSIFIER')
您可以選擇設置分類器“classifier_camera”的屬性。
exec ctx_ddl.set_attribute('classifier_camera','MAX_FEATURES','1000'); exec ctx_ddl.set_attribute('classifier_camera','NUM_ITERATIONS','600');
6-5. 索引訓練集
在訓練表上創(chuàng)建索引。該索引僅用于其關(guān)聯(lián)的元數(shù)據(jù),因此可以使用“nopopulate”選項創(chuàng)建,并且速度非常快。對于經(jīng)過訓練的分類器,您確實需要使用 AUTO_LEXER,我們將允許它使用默認的英語詞法分析器 (BASIC_LEXER)。
create index training_idx on training_camera(train_text) indextype is ctxsys.context parameters ('nopopulate');
6-6. 訓練分類器
過程 SA_TRAIN_MODEL(SA 用于情感分析)獲取有關(guān)訓練和類別表(及其各個列)的信息,以及我們剛剛創(chuàng)建的索引和分類器首選項的名稱。然后,這將生成一個模型,其名稱在第一個參數(shù)中給出 - 在本例中為“my_clsfier”
begin ctx_cls.sa_train_model ( clsfier_name => 'my_clsfier', index_name => 'training_idx', docid => 'train_id', cattab => 'training_category', catdocid => 'doc_id', catid => 'category', pref_name => 'classifier_camera' ); end;
6-7. 使用經(jīng)過訓練的分類器運行情感分析
運行情感分析的過程與上次非常相似,只是這次我們需要提供分類器名稱,而不是允許其默認。
請記住,我們在camera_reviews 表上已經(jīng)有一個“nopopulate”文本索引 - 如果我們在上一步中沒有創(chuàng)建它,我們需要在使用新分類器之前在此處創(chuàng)建它。
select ctx_doc.sentiment_aggregate( index_name => 'camera_revidx', textkey => review_id, clsfier_name => 'my_clsfier' ) sentiment, review_text from camera_reviews;
我們還可以在同一個查詢中運行經(jīng)過訓練和未經(jīng)訓練的分類器,以比較兩者的效率。當然,這是一個精心選擇訓練詞的人為示例,但在現(xiàn)實世界中,假設訓練集大小合理,您應該會看到經(jīng)過訓練的分類器具有明顯更好的性能。
select review_text, ctx_doc.sentiment_aggregate('camera_revidx', review_id) as default_sentiment, ctx_doc.sentiment_aggregate('camera_revidx', review_id, clsfier_name => 'my_clsfier') as trained_sentiment from camera_reviews order by trained_sentiment;
You can find more details of sentiment analysis here: [Sentiment Analysis](You can find more details of sentiment analysis here: Sentiment Analysis.
).
refer: Full-Text Search in Oracle Database ShareStart
完結(jié)!
相關(guān)文章
DBF 文件恢復 ORACLE 數(shù)據(jù)庫的方法
這篇文章主要介紹了DBF 文件 ORACLE 數(shù)據(jù)庫恢復的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01PL/SQL中編寫Oracle數(shù)據(jù)庫分頁的存儲過程
這篇文章主要介紹了 PL/SQL中編寫Oracle數(shù)據(jù)庫分頁的存儲過程,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-06-06Oracle的數(shù)據(jù)表中行轉(zhuǎn)列與列轉(zhuǎn)行的操作實例講解
這篇文章主要介紹了Oracle數(shù)據(jù)表中行轉(zhuǎn)列與列轉(zhuǎn)行的操作方法,這里分靜態(tài)和動態(tài)情況作出了分類討論,需要的朋友可以參考下2015-12-12