2012-02-13 82 views
1

我有一個很大的xml數據庫(30 000個文件,1.3 Go)。此數據庫中的一個文件列出數據庫中存在的所有其他文件。我的目標是「簡單地」檢查列出的所有文件是否存在於數據庫中。但我不能關心文件的名稱,只能處理文檔中的XML代碼。XQuery - 爲BIG數據庫優化查詢

這是類似的東西:

declare variable $root := fn:collection(); 

declare function local:isValid($fileCode) { 

let $fileSearchedIdentCode := $root/dmodule/identity/dmCode 
return 
$fileCode/@attribute1 = $fileSearchedIdentCode/@attribute1 and 
$fileCode/@attribute2 = $fileSearchedIdentCode/@attribute2 and 
$fileCode/@attribute3 = $fileSearchedIdentCode/@attribute3 

}; 

<result> 
{ 
for $fileCode in $root/file[identity/@fileType eq 'listOfFiles']/fileContent/fileEntry/fileCode 
return 
    if (local:isValid($fileCode)) 
    then <filePresent>1</filePresent> 
    else <fileNonPresent>2</fileNonPresent> 

} 
</result> 

上面的代碼運行一個小DATABSE但對於我的,它是需要時間的數量驚人。

SO,我不知道是否有人能幫助我提高,以便在合理的時間來執行它的代碼;)

(我的數據庫被索引)

感謝您的幫助!

Johann

+0

我不能編輯我的帖子:(對不起,不說「你好」 – Johann 2012-02-13 14:30:14

+0

說你好不是自定義的。你能告訴你使用哪個數據庫嗎?使用索引可能需要使用專有擴展,或者優化表達式以匹配內置優化30k文檔並不多,但足以想要使用索引 – grtjn 2012-02-13 14:44:25

+0

我必須在幾個數據庫(baseX,marklogic,oracle db XML和qizx)上創建一個基準測試,目前我使用的是BaseX。 – Johann 2012-02-13 14:48:54

回答

3

看起來屬性索引不適用於local:isValid函數中的屬性檢查。您可以通過重寫他們實現,作爲XPath的謂詞:

declare variable $root := fn:collection(); 

declare function local:isValid($fileCode) { 
    $root/dmodule/identity/dmCode[@attribute1 = $fileCode/@attribute1 
    and @attribute2 = $fileCode/@attribute2 
    and @attribute3 = $fileCode/@attribute3] 
}; 

<result> { 
    for $fileCode in $root/file[identity/@fileType = 'listOfFiles']/fileContent/fileEntry/fileCode 
    return 
    if (local:isValid($fileCode)) 
     then <filePresent>1</filePresent> 
     else <fileNonPresent>2</fileNonPresent> 
}</result> 

這些變化之後,查詢信息鑑於BaseX告訴我,該指數用於:

Compiling: 
- pre-evaluating fn:collection() 
- rewriting And expression to predicate(s) 
- rewriting fn:boolean(@*:attribute1 = $fileCode/@attribute1) 
- rewriting fn:boolean(@*:attribute2 = $fileCode/@attribute2) 
- rewriting fn:boolean(@*:attribute3 = $fileCode/@attribute3) 
- applying attribute index 
- applying attribute index 

和評估時間滴從4'500ms到〜20ms爲我的測試數據。

+0

當我測試你的解決方案時,有一些奇怪的東西: BaseX無法執行某些內容......即使對於小測試,它也會以「Please wait ...」運行,運行並再次運行。 我誤解了配置嗎? – Johann 2012-02-13 16:01:28

+0

您是否可以創建可管理大小的示例集合,以便我們可以測試我們的建議?這樣做很容易。 – 2012-02-13 16:38:12

+0

事實上,我只用5個XML文件(28 Mo)進行測試,當我點擊「運行」按鈕時,它被寫爲「Please Wait ...」,並且沒有任何反應。 – Johann 2012-02-13 17:03:28

0

是否有助於用等號(=)替換「eq」?

+0

它不會改變任何性能......我剛剛測試過 – Johann 2012-02-13 15:33:43

+0

你嘗試過不同版本的basex(例如BaseX 7 vs 7.1)?一般來說,像您這樣的查詢應該使用現有的(自動創建的)值索引進行優化,所以請隨時爲我們提供一些匿名化的XML片段! – 2012-02-14 08:54:11

1

您沒有將eXist-db包含在您的測試系統列表中,但是如果您有興趣用數據對其進行基準測試,那麼有一篇關於優化查詢並智能地使用索引來加速eXist性能的文章-D b。見http://exist-db.org/exist/tuning.xml。您發佈的查詢應該沒有修改就能正常工作,但文章中的建議一定會幫助您提高性能。如果您需要幫助,請隨時發佈到現有的郵件列表。不管你使用哪種系統,我都會非常感興趣地知道你的結果 - 而不僅僅是我 - 我認爲這會引起廣泛的興趣。

祝你好運!

3

對於MarkLogic,您需要注意索引查找僅在某些表達式和函數中發生。在這種情況下,您需要更緊湊的代碼。下面是應該產生相同的結果,但會以簡單的方式使用索引的一種形式:

<result> 
{ 
    for $fileCode in 
     collection()/ 
     file[identity/@fileType eq "listOfFiles"]/ 
     fileContent/ 
     fileEntry/ 
     fileCode 
    let $fc1 := $fileCode/@attribute1/string() 
    let $fc2 := $fileCode/@attribute2/string() 
    let $fc3 := $fileCode/@attribute3/string() 
    return 
     if (collection()/ 
      dmodule/ 
      identity/ 
      dmCode[ 
      @attribute1 eq $fc1][ 
      @attribute2 eq $fc2][ 
      @attribute3 eq $fc3]) 
     then <filePresent>1</filePresent> 
     else <fileNonPresent>2</fileNonPresent> 
    } 
</result> 

但是該代碼將每listOfFiles項,這不是最佳執行一個數據庫查詢。

可以進一步優化。首先,MarkLogic是一個面向文檔的數據庫,每個文檔都有一個唯一的URI。因此,如果您只將三個屬性值編碼到每個文檔URI中,效率會更高。我們可能會使用類似string-join(($fc1, $fc2, $fc3), '/')來構建URI。然後,您可以使用doc()調用來檢查每個值,這比XPath查找更有效率 - 即使在使用索引時也是如此。一旦做出更改,listOfFiles文檔可能會存儲URI而不是屬性值。

二,我認爲結果格式不是很有用。它告訴你一些文件丟失,但沒有。我會重構,以便代碼只返回缺少的文檔URI。我們也可能在MarkLogic中啓用額外的索引:URI詞典。這會自動維護所有文檔URI的值索引,有點像您的listOfFiles文檔。使用URI的詞彙,我可以這樣寫:

<result>{ 
    let $uris := 
     collection()/ 
     file[identity/@fileType eq "listOfFiles"]/ 
     fileContent/ 
     fileEntry/ 
     fileCode/ 
     string-join(
     (@attribute1/string(), 
     @attribute2/string(), 
     @attribute3/string()), 
     "/") 
    let $uris-present := cts:uris((), "document", cts:document-query($uris)) 
    for $uri in $uris 
    where not($uri = $uris-present) 
    return <missing>{ $uri }</missing> 
}</result> 

,只需要一個數據庫查詢,並不會在內存中的必要的工作的其餘部分。它應該比原始查詢或我的第一次迭代縮放得更好。如果你不跟我的結果格式的返工同意,並仍然希望看到的結果對於每個輸入fileCode,你可以重構...where...return...條款列入...return...if...then...else...在原始查詢。

務必在https://github.com/marklogic/cq使用的配置文件的工具 - 它可以幫助您試試最佳化替代和現貨的機會。

+0

快速附錄re:剖析。一個類似的配置文件工具現在作爲查詢控制檯的一部分附帶(點瀏覽器到'http:// yourserver:8000/qconsole'),所以如果你運行的是MarkLogic 5,你不會真的需要cq。 – 2012-02-13 21:12:48

1

MarkLogic應該處理您的查詢速度快,如果你定義每個您使用在比較屬性的屬性範圍的索引。

您可以通過MarkLogic管理UI做到這一點(HTTP:// 主機名:8001):

  • 在左側選擇在數據庫
  • 選擇屬性範圍索引數據庫
  • 選擇添加到定義一個新的屬性範圍指數
  • 指定元素(dmcode)和屬性(ATTRIBUTE1,attribute2,attribute3)引用該區域指數(不要忘了指定命名空間,如果你的元素是在證書ain命名空間)。
  • 單擊確定以創建範圍索引。

您正在使用什麼版本的MarkLogic的? 如果使用的是MarkLogic 5,你也可以使用查詢控制檯來測試您的查詢:

(HTTP:// 主機名:8000/qconsole)

隨意問,如果你有任何問題/讓我知道事情的後續。 我來自MarkLogic,很樂意提供幫助。