查詢和建立索引的最佳實務 best-practices-for-queries-and-indexing
除了在AEM 6轉換至Oak外,查詢和索引的管理方式也發生了一些重大變化。 在Jackrabbit 2下,所有內容預設都已編制索引,且可供自由查詢。 在Oak中,必須在oak:index
節點下手動建立索引。 可以在沒有索引的情況下執行查詢,但對於大型資料集,查詢將執行緩慢,甚至中止。
本文概述何時建立索引以及何時不需要索引、避免在不需要查詢時使用查詢的技巧,以及最佳化索引和查詢以儘可能最佳執行的相關提示。
另外,請務必閱讀有關撰寫查詢和索引的Oak檔案。 除了索引是AEM 6中的新概念之外,從先前的AEM安裝移轉程式碼時,也需要考慮Oak查詢中的語法差異。
何時使用查詢 when-to-use-queries
存放庫和分類法設計 repository-and-taxonomy-design
在設計存放庫的分類法時,需要考慮幾個因素。 其中包括存取控制、本地化、元件和頁面屬性繼承等。
在設計解決這些問題的分類法時,考慮索引設計的「可通行性」也很重要。 在此情境中,可周遊性是分類法的能力,可允許根據其路徑以可預測的方式存取內容。 這將造就比需要執行許多查詢的系統更易於維護的效能更高的系統。
此外,在設計分類法時,考慮排序是否重要也很重要。 若不需要明確排序,且預期會有許多同層級節點,則最好使用無序節點型別,例如sling:Folder
或oak:Unstructured
。 在需要排序的情況下,nt:unstructured
和sling:OrderedFolder
更合適。
元件中的查詢 queries-in-components
由於查詢可能是在AEM系統上執行的最繁重的操作之一,因此最好在元件中避免查詢。 每次轉譯頁面時執行數個查詢通常會降低系統效能。 有兩種策略可用來在轉譯元件時避免執行查詢: 周遊節點 和 預先擷取結果。
周遊節點 traversing-nodes
如果設計存放庫的方式允許事先瞭解所需資料的位置,則可以部署從必要路徑擷取此資料的程式碼,而無需執行查詢來尋找它。
這方面的一個範例是呈現適合特定類別的內容。 其中一種方式是使用類別屬性來組織內容,而可以查詢該屬性以填入顯示類別中專案的元件。
更好的方式是依類別以分類法建構此內容,以便手動擷取。
例如,如果內容儲存在類似以下的分類法中:
/content/myUnstructuredContent/parentCategory/childCategory/contentPiece
可以簡單地擷取/content/myUnstructuredContent/parentCategory/childCategory
節點,剖析其子系並用於演算元件。
此外,當您處理小型或同質結果集時,周遊存放庫並收集所需節點會比手工建立查詢以傳回相同的結果集更快。 一般而言,應儘可能避免查詢。
預先擷取結果 prefetching-results
有時候,元件周圍的內容或需求不允許使用節點周遊作為擷取所需資料的方法。 在這些情況下,需要在元件轉譯之前執行所需的查詢,以確保一般使用者的最佳效能。
如果元件所需的結果可在編寫時計算,且預期內容不會變更,則可在作者在對話方塊中套用設定時執行查詢。
如果資料或內容會定期變更,則可依排程或透過監聽器執行查詢,以更新基礎資料。 然後,可以將結果寫入存放庫中的共用位置。 任何需要此資料的元件都可以從此單一節點提取值,而不需要在執行階段執行查詢。
查詢最佳化 query-optimization
執行未使用索引的查詢時,會記錄有關節點周遊的警告。 如果這是經常執行的查詢,請建立索引。 若要判斷指定查詢使用的索引,建議使用說明查詢工具。 如需詳細資訊,可以為相關搜尋API啟用DEBUG記錄。
執行複雜查詢時,在某些情況下,將查詢劃分為多個較小的查詢,並在事實更高效後透過程式碼聯結資料。 這些案例的建議是比較兩種方法的效能,以判斷哪一種選項更適合相關使用案例。
AEM允許以下列三種方式之一寫入查詢:
- 透過QueryBuilder API (建議使用)
- 使用XPath (建議)
- 使用SQL2
雖然所有查詢在執行前都會轉換為SQL2,但查詢轉換的額外開銷極小,因此,選擇查詢語言時最大的考量將是開發團隊的可讀性和舒適度。
說明查詢工具 the-explain-query-tool
和任何查詢語言一樣,最佳化查詢的第一步是瞭解它將如何執行。 若要啟用此活動,您可以使用作業儀表板的說明查詢工具。 使用此工具,可以插入查詢並加以說明。 如果查詢會導致大型存放庫和執行時間以及使用的索引發生問題,則會顯示警告。 此工具也可以載入緩慢和熱門查詢的清單,然後加以說明和最佳化。
查詢的DEBUG記錄 debug-logging-for-queries
若要取得有關Oak如何選擇要使用的索引以及查詢引擎實際執行查詢的方式的其他資訊,可以為以下套件新增 DEBUG 記錄設定:
- org.apache.jackrabbit.oak.plugins.index
- org.apache.jackrabbit.oak.query
- com.day.cq.search
完成查詢偵錯後,請務必移除此記錄器。 它通常會輸出大量活動,最終可能會將記錄檔填滿磁碟。
如需如何執行此動作的詳細資訊,請參閱記錄檔案。
索引統計資料 index-statistics
Lucene會註冊一個JMX Bean,以提供索引內容的詳細資訊,包括每個索引中存在的檔案大小和數量。
您可以存取位於https://server:port/system/console/jmx
的JMX主控台來存取它
登入JMX主控台後,請搜尋 Lucene索引統計資料 以找到它。 其他索引統計資料可以在 IndexStats MBean中找到。
如需查詢統計資料,請檢視名為 Oak查詢統計資料 的MBean。
如果要使用Luke之類的工具來深入瞭解您的索引,您必須使用Oak主控台將索引從NodeStore
傾印到檔案系統目錄。 如需如何執行此動作的說明,請閱讀Lucene檔案。
您也可以以JSON格式擷取系統中的索引。 若要這麼做,您必須存取https://server:port/oak:index.tidy.-1.json
查詢限制 query-limits
開發期間
為oak.queryLimitInMemory
(例如10000)和Oak設定低臨界值。 queryLimitReads
(例如5000)並在點選UnsupportedOperationException時最佳化昂貴查詢,指出「查詢讀取超過x個節點……」
這有助於避免資源密集的查詢(亦即,不受任何索引支援或較少涵蓋範圍索引所支援)。 例如,讀取100萬個節點的查詢會導致I/O增加,並對整體應用程式效能產生負面影響。 應分析和最佳化任何因上述限制而失敗的查詢。
Post — 部署 post-deployment
-
監視查詢記錄以觸發大型節點周遊或大型棧積記憶體消耗: "
*WARN* ... java.lang.UnsupportedOperationException: The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
- 最佳化查詢以減少周遊的節點數
-
監視記錄以找出觸發大型棧積記憶體消耗的查詢:
*WARN* ... java.lang.UnsupportedOperationException: The query read more than 500000 nodes in memory. To avoid running out of memory, processing was stopped
- 最佳化查詢以降低棧積記憶體耗用量
對於AEM 6.0 - 6.2版本,您可以透過AEM啟動指令碼中的JVM引數調整節點周遊的臨界值,以防止大型查詢使環境過載。
建議的值為:
-Doak.queryLimitInMemory=500000
-Doak.queryLimitReads=100000
在AEM 6.3中,上述兩個引數是現成可預先設定的,並可透過OSGi QueryEngineSettings持續存在。
如需詳細資訊,請參閱: https://jackrabbit.apache.org/oak/docs/query/query-engine.html#Slow_Queries_and_Read_Limits
建立有效索引的秘訣 tips-for-creating-efficient-indexes
我應該建立索引嗎? should-i-create-an-index
建立或最佳化索引時,首先要問的問題是給定情況下是否需要索引。 如果您只打算透過批次處理在系統的非尖峰時間執行一次有問題的查詢,最好完全不要建立索引。
建立索引後,每次更新索引資料時,索引也必須更新。 由於這會對系統造成效能影響,因此應該僅在需要索引時建立索引。
此外,只有在索引中包含的資料足夠獨特,足以保證使用時,索引才有用。 考量書籍中的索引及其涵蓋的主題。 當在文字中索引一組主題時,通常會有數百或數千個專案,這可讓您快速跳至頁面的子集,以快速找到您要尋找的資訊。 如果該索引只有兩個或三個專案,而每個專案都指向數百個頁面,則該索引將沒有用處。 這個概念同樣適用於資料庫索引。 如果只有幾個唯一值,則索引將沒有用處。 話雖如此,索引也可能變得太大而無法使用。 若要檢視索引統計資料,請參閱上述索引統計資料。
Lucene或屬性索引? lucene-or-property-indexes
Lucene索引在Oak 1.0.9中引入,並針對AEM 6首次推出時引入的屬性索引提供一些強大的最佳化功能。 在決定使用Lucene索引或屬性索引時,請考慮以下因素:
- Lucene索引比屬性索引提供更多的功能。 例如,屬性索引只能索引單一屬性,而Lucene索引可以包含多個屬性。 如需Lucene索引中所有可用功能的詳細資訊,請參閱檔案。
- Lucene索引為非同步。 雖然這可提供顯著的效能提升,但也會導致在資料寫入存放庫和更新索引之間發生延遲。 如果讓查詢傳回100%正確結果很重要,則需要屬性索引。
- 由於不同步,Lucene索引無法強制唯一性限制。 如果需要,則需要放置屬性索引。
一般而言,除非迫切需要使用屬性索引,否則建議您使用Lucene索引,如此您才能獲得更高效能和彈性的優點。
Solr索引 solr-indexing
依預設,AEM也支援Solr索引。 這可用來支援全文檢索搜尋,但也可用來支援任何型別的JCR查詢。 當AEM執行個體沒有足夠的CPU容量來處理大量搜尋部署(例如同時擁有大量使用者的搜尋驅動網站)所需的查詢數時,應該考慮Solr。 或者,Solr也可以以爬行者程式為基礎的方法實作,以使用平台的一些更進階的功能。
Solr索引可以設定為針對開發環境在AEM伺服器上執行內嵌,也可以解除安裝到遠端執行個體,以改善生產和中繼環境的搜尋擴充性。 雖然解除安裝搜尋可改善擴充性,但會導致延遲,因此除非有需要,否則不建議使用。 如需有關如何設定Solr整合以及如何建立Solr索引的詳細資訊,請參閱Oak查詢和索引檔案。
使用此方法的缺點是,雖然依預設,AEM查詢會遵循ACL,因此會隱藏使用者無法存取的結果,但外部化搜尋至Solr伺服器將無法支援此功能。 如果要以這種方式將搜尋外部化,則必須格外注意確保使用者不會看到他們不應該看到的結果。
在可能需要彙總來自多個來源的搜尋資料的情況下,此方法可能適用的潛在使用案例。 例如,您的網站可能會託管在AEM上,而第二個網站則託管在協力廠商平台上。 Solr可設定為對兩個網站的內容進行編目,並將它們儲存在彙總索引中。 這將允許跨網站搜尋。
設計考量事項 design-considerations
適用於Lucene索引的Oak檔案列出在設計索引時要注意的幾個事項:
-
如果查詢使用不同的路徑限制,請使用
evaluatePathRestrictions
。 這可讓查詢傳回指定路徑下的結果子集,然後根據查詢篩選它們。 否則,查詢會搜尋與存放庫中查詢引數相符的所有結果,然後根據路徑篩選它們。 -
如果查詢使用排序,請為排序的屬性定義明確的屬性,並為它將
ordered
設定為true
。 如此一來,便可在索引中依此順序排序結果,並節省查詢執行時耗費大量資源的排序作業。 -
只將所需的內容放入索引。 新增不需要的功能或屬性會導致索引增加並減慢效能。
-
在屬性索引中,擁有唯一的屬性名稱有助於縮小索引的大小,但對於Lucene索引,應使用
nodeTypes
和mixins
以實現有凝聚力的索引。 查詢特定nodeType
或mixin
會比查詢nt:base
更有效。 使用此方法時,請為有問題的nodeTypes
定義indexRules
。 -
如果您的查詢只在某些路徑下執行,則在這些路徑下建立這些索引。 索引不需要位於存放庫的根目錄。
-
當所有要編制索引的屬性都相關時,請使用單一索引,以允許Lucene儘可能以原生方式評估更多屬性限制。 此外,即使執行聯結,查詢也只使用一個索引。
CopyonRead copyonread
如果從遠端儲存NodeStore
,則可以啟用名為CopyOnRead
的選項。 選項會在讀取遠端索引時,將其寫入本機檔案系統。 這有助於改善經常針對這些遠端索引執行的查詢效能。
您可以在 LuceneIndexProvider 服務底下的OSGi主控台中設定此專案,並且自Oak 1.0.13起預設為啟用。
移除索引 removing-indexes
移除索引時,一律建議將type
屬性設定為disabled
來暫時停用索引,並進行測試以確保您的應用程式在實際刪除索引之前可以正常運作。 索引在停用時不會更新,因此如果重新啟用,可能沒有正確的內容,並且可能需要重新編制索引。
移除TarMK執行個體上的屬性索引後,必須執行壓縮以回收任何使用中的磁碟空間。 對於Lucene索引,實際的索引內容存在於BlobStore中,因此需要資料存放區記憶體回收。
移除MongoDB執行個體上的索引時,刪除成本與索引中的節點數量成比例。 由於刪除大型索引可能會造成問題,建議方法是使用 oak-mongo.js 之類的工具,僅在維護期間停用索引並刪除索引。 請注意,不應將此方法用於一般節點內容,因為這會造成資料不一致。
JCR查詢速查表 jcrquerycheatsheet
為了支援建立有效的JCR查詢和索引定義,JCR查詢速查表可供下載,並可在開發期間作為參考使用。 它包含QueryBuilder、XPath和SQL-2的範例查詢,涵蓋了在查詢效能方面行為不同的多個案例。 此外,也提供如何建立或自訂Oak索引的建議。 本速查表內容適用於AEM 6.5和AEM as a Cloud Service。
重新索引 re-indexing
本節概述 僅 重新索引Oak索引的可接受原因。
除了下面列出的原因以外,起始Oak索引的重新索引並 不會 變更行為或解決問題,並且不必要地增加AEM上的負載。
除非下表中有原因說明,否則應避免重新索引Oak索引。
Oak索引設定變更 oak-index-configuration-changes
重新索引Oak索引唯一可接受的不錯誤條件是Oak索引的設定已變更。
在重新索引時,應一律適當考量其對AEM整體效能的影響,並在活動較少或維護期間執行。
以下詳細說明可能的問題以及解決方法:
屬性索引定義變更 property-index-definition-change
Lucene索引定義變更 lucene-index-definition-change
-
適用於/if:
- 所有Oak版本
- 僅lucene索引
-
症狀:
- Lucene索引不包含預期的結果
- 查詢結果未反映索引定義的預期行為
- 查詢計畫未根據索引定義報告預期輸出
-
如何驗證:
- 確認已使用Lucene索引統計資料JMX Mbean (LuceneIndex)方法
diffStoredIndexDefinition
變更索引定義。
- 確認已使用Lucene索引統計資料JMX Mbean (LuceneIndex)方法
-
如何解決:
錯誤和特殊情況 erring-and-exceptional-situations
下表說明重新索引Oak索引解決此問題的唯一可接受錯誤和例外情況。
如果AEM發生不符合下列准則的問題,請 不 重新索引任何索引,因為這樣將無法解決問題。
以下詳細說明可能的問題以及解決方法:
缺少Lucene索引二進位檔 lucene-index-binary-is-missing
-
適用於/if:
- 所有Oak版本
- 僅lucene索引
-
症狀:
- Lucene索引不包含預期的結果
-
如何驗證:
- 錯誤記錄檔包含例外狀況,指出Lucene索引的二進位檔遺失
-
如何解決:
-
執行周遊存放庫檢查;例如:
http://localhost:4502/system/console/repositorycheck
周遊存放庫可確定是否缺少其他二進位檔(lucene檔案除外)
-
如果缺少lucene索引以外的二進位檔案,請從備份還原
-
否則,重新索引 所有 lucene索引
-
注意:
此狀況表示資料存放區設定錯誤,可能會導致ANY二進位(例如資產二進位檔)遺失。
在此情況下,請還原到儲存區域的最後一個已知良好版本,以復原所有遺失的二進位檔案。
-
Lucene索引二進位檔已損毀 lucene-index-binary-is-corrupt
如何重新索引 how-to-re-index
重新索引屬性索引 re-indexing-property-indexes
-
使用oak-run.jar重新索引屬性索引
-
在屬性索引上將async-reindex屬性設定為true
[oak:queryIndexDefinition]@reindex-async=true
-
透過 PropertyIndexAsyncReindex MBean,使用Web主控台非同步地重新索引屬性索引;
例如,
重新索引Lucene屬性索引 re-indexing-lucene-property-indexes
-
使用oak-run.jar重新索引 Lucene屬性索引。
-
在lucene屬性索引上,將async-reindex屬性設定為true
[oak:queryIndexDefinition]@reindex-async=true
二進位檔的文字預先擷取 text-pre-extraction-of-binaries
文字預先擷取是指透過獨立程式,直接從資料存放區從二進位檔擷取及處理文字的程式,並直接將擷取的文字公開給Oak索引的後續重新/索引。
- 建議使用Oak文字預先擷取,在具有大量檔案(二進位檔)的存放庫上重新編列/索引Lucene索引,這些檔案包含可擷取文字(例如PDF、Word檔案、PPT、TXT等),且符合透過已部署的Oak索引進行全文檢索搜尋的資格;例如
/oak:index/damAssetLucene
。 - 文字預先擷取僅有利於Lucene索引的重新編列/索引,而非Oak屬性索引,因為屬性索引不會從二進位檔案中擷取文字。
- 當對大量文字的二進位檔(PDF、Doc、TXT等)進行全文重新索引時,文字預先擷取會有很高的正面影響,而影像存放庫將不會享有相同的效率,因為影像不包含可擷取的文字。
- 文字預先擷取會以特別有效率的方式執行全文檢索搜尋相關文字的擷取,並以特別有效率的方式將其公開給Oak重新編制/索引過程。
何時可以使用文字預先擷取? when-can-text-pre-extraction-be-used
正在重新索引已啟用二進位擷取的 現有 lucene索引
- 重新索引處理儲存庫中的 所有 候選內容;當要從中擷取全文檢索的二進位檔數量眾多或複雜時,AEM上會增加執行全文檢索擷取的運算負擔。 文字預先擷取會將文字擷取的「運算成本高的工作」移入直接存取AEM資料存放區的隔離處理序,避免AEM的額外開銷和資源爭用。
支援將 新 lucene索引部署至已啟用二進位擷取的AEM
- 當新索引(已啟用二進位擷取)部署到AEM時,Oak會在下次非同步全文檢索索引執行時自動索引所有候選內容。 由於上述重新索引中所述的相同原因,這可能會導致AEM上的過度載入。
何時可以使用文字預先擷取? when-can-text-pre-extraction-not-be-used
文字預先擷取無法用於新增到存放庫的新內容,也不需要。
新內容新增到存放庫時,將透過非同步全文檢索索引程式(預設為每5秒一次)以自然和遞增方式索引。
在AEM的正常運作中(例如透過網頁UI或程式化擷取Assets上傳Assets),AEM會自動以增量方式將新的二進位內容編入全文索引。 由於資料量是遞增的,而且相對較少(大約是可在5秒內保留到存放庫的資料量),AEM可以在索引期間從二進位檔執行全文擷取,而不會影響整體系統效能。
使用文字預先擷取的先決條件 prerequisites-to-using-text-pre-extraction
-
您將重新索引執行全文檢索二進位擷取的lucene索引,或部署將現有內容的全文檢索二進位索引的新索引
-
要從中預先擷取文字的內容(二進位檔案)必須位於存放庫中
-
用於產生CSV檔案並執行最終重新索引的維護時段
-
Oak版本: 1.0.18+, 1.2.3+
-
oak-run.jar版本1.7.4+
-
儲存可透過索引AEM例項存取之擷取文字的檔案系統資料夾/共用
- 文字預先解壓縮OSGi設定需要解壓縮文字檔案的檔案系統路徑,因此必須可直接從AEM執行個體(本機磁碟機或檔案共用掛載)存取
如何執行文字預先擷取 how-to-perform-text-pre-extraction
產生要預先擷取的內容清單
在維護期間/低使用期間執行步驟1(a-b),因為在此作業期間節點存放區被周遊,這可能會導致系統承受大量負載。
1a。 執行oak-run.jar --generate
以建立將預先擷取其文字的節點清單。
1b. 節點清單(1a)會以CSV檔案形式儲存至檔案系統
每次執行--generate
時都會周遊整個節點存放區(如Oak-run命令中的路徑所指定),且會建立 新的 CSV檔案。 CSV檔案 不 會在文字預先擷取程式的分散執行之間重複使用(步驟1 - 2)。
預先擷取文字至檔案系統
步驟2(a-c)只與資料存放區互動,所以可在AEM的正常操作期間執行。
2a。 執行oak-run.jar --tika
以預先擷取在(1b)中產生之CSV檔案中所列舉之二進位節點的文字
2b. 在(2a)中起始的程式會直接存取資料存放區中CSV定義的二進位節點,並擷取文字。
2c。 擷取的文字會以可由Oak重新索引程式(3a)擷取的格式儲存在檔案系統中
預先擷取的文字會在CSV中由二進位指紋識別。 如果二進位檔案相同,則可在AEM執行個體間使用相同的預先擷取文字。 由於AEM Publish通常是AEM Author的子集,從AEM Author預先擷取的文字通常也可用於重新索引AEM Publish (假設AEM Publish具有擷取文字檔案的檔案系統存取權)。
預先擷取的文字可以隨著時間逐漸新增至。 文字預先擷取將略過先前擷取二進位檔的擷取,因此最佳實務是保留預先擷取的文字,以防未來必須再次進行重新索引(假設擷取的內容不會太大)。 如果是,請評估在過渡期間壓縮內容(因為文字壓縮得不錯)。
重新索引Oak索引,從擷取的文字檔取得全文
在維護/低使用期間執行重新索引(步驟3a-b),因為在此作業期間節點存放區被周遊,這可能會導致系統承受大量負載。
3a。 已在AEM中叫用Lucene索引的重新索引。
3b. Apache Jackrabbit Oak DataStore PreExtractedTextProvider OSGi設定(設定為透過檔案系統路徑指向擷取的文字)會指示Oak從擷取的檔案取得全文文字,並避免直接點選及處理儲存於存放庫中的資料。