情節CMS和商業的搜索插件
提供了支持.NET 6+的版本。有關詳細信息,請聯繫Kristian Borg。
首先,您需要創建索引。通過嵌入式菜單搜索引擎 - >管理和狀態轉到管理頁面,然後單擊Create indices按鈕。
這將在您的網站上每種語言創建一個索引。如果您安裝了商務插件,還將創建針對目錄內容的其他索引。

將為您的網站上的每種活動語言創建一個單獨的索引。如果以後添加更多語言,則需要重複此過程。
您可以使用singleton Epinova.ElasticSearch.Core.Conventions.Indexing以編程方式配置設置。每個AppDomain僅在一個可初始化的模塊或Application_start()中進行一次。
樣本配置類:
public static class SearchConfig
{
public static void Init ( )
{
Epinova . ElasticSearch . Core . Conventions . Indexing . Instance
. ExcludeType < ErrorPage > ( )
. ExcludeType < StartPage > ( )
. ExcludeRoot ( 42 )
. IncludeFileType ( "pdf" )
. IncludeFileType ( "docx" )
. ForType < ArticlePage > ( ) . IncludeProperty ( x => x . Changed )
. ForType < ArticlePage > ( ) . IncludeField ( x => x . GetFoo ( ) )
. ForType < ArticlePage > ( ) . IncludeField ( "TenYearsAgo" , x => DateTime . Now . AddYears ( - 10 ) )
. ForType < ArticlePage > ( ) . EnableSuggestions ( x => x . Title )
. ForType < TagPage > ( ) . EnableSuggestions ( )
. ForType < ArticlePage > ( ) . EnableHighlighting ( x => x . MyField )
. ForType < ArticlePage > ( ) . StemField ( x => x . MyField ) ;
}
}解釋不同選項:
ExcludeType :這種類型不會被索引。也支持基礎類和界面。可以通過ExcludeFromSearchAttribute來裝飾您的類型來實現這一目標
ExcludeRoot :這個節點及其子女不會被索引。通常在Episerver Page-Tree中的節點ID。
IncludeFileType :定義應索引的文件類型的擴展名。另請參見配置中的<files>節點。
ForType :特定類型的索引規則的起點。本身沒有做任何事情,但可以訪問以下選項:
IncludeField :定義要索引的自定義屬性。例如一種擴展方法獲取外部數據或執行複雜的聚合。
EnableSuggestions :通過Lambda表達式提供此類類型的AutoSuggest數據,或者來自所有屬性。
IncludeProperty :與使用[可搜索]裝飾屬性相同的效果。如果您不控制模型源,則可以使用。
EnableHighlighting :添加要突出顯示的其他字段。
StemField :定義應用當前語言分析屬性。將始終分析名為MainIntro , MainBody和Description的屬性。
該模塊試圖遵循與Episerver相同的約定,這意味著類型string和XhtmlString的所有屬性都將被索引,除非用[Searchable(false)]明確裝飾。可以通過使用[Searchable]或上面的約定來裝飾其他屬性來索引它們。用[Searchable]索引內容ContentArea confetarea。
SearchResult result = service
. Search ( "bacon" )
. GetResults ( ) ; SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. GetResults ( ) ; SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. InField ( x => x . MainIntro )
. InField ( x => x . MainBody )
. InField ( x => x . MyCustomMethod ( ) )
. GetResults ( ) ;搜索以短語開頭的索引單詞:
string [ ] suggestions = service . GetSuggestions ( "baco" ) ;使用默認長度自動(推薦):
SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. Fuzzy ( )
. GetResults ( ) ;特定長度:
SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. Fuzzy ( 4 )
. GetResults ( ) ;謹慎使用,因為這不支持諸如Stemming之類的功能。
SearchResult result = service
. WildcardSearch < ArticlePage > ( "*bacon*" )
. GetResults ( ) ; SearchResult result = service
. WildcardSearch < ArticlePage > ( "me?t" )
. GetResults ( ) ; SearchResult result = service
. SimpleQuerystringSearch < ArticlePage > ( "(bacon | ham) melt -cheese" )
. GetResults ( ) ;有限的運營商:
SearchResult result = service
. SimpleQuerystringSearch < ArticlePage > ( " " bacon melt " sandwi*" ,
defaultOperator : Operator . And ,
allowedOperators :
SimpleQuerystringOperators . Prefix |
SimpleQuerystringOperators . Phrase ) ;
)
. GetResults ( ) ;請參閱https://www.elastic.co/guide/en/elasticsearch/reference/current/querrent/query-dsl-simple-query-query-query-string-query.html有關語法的信息。
使用類型Epinova.ElasticSearch.Core.Models.Properties.GeoPoint的屬性,您可以執行基於地理的過濾。
示例模型:
public class OfficePage : StandardPage
{
[ Display ]
public virtual double Lat { get ; set ; }
[ Display ]
public virtual double Lon { get ; set ; }
// Helper property, you could always roll an editor for this
public GeoPoint Location => new GeoPoint ( Lat , Lon ) ;
} 根據其上左上角和右下角找到方形區域內的點。
var topLeft = ( 59.9277542 , 10.7190847 ) ;
var bottomRight = ( 59.8881646 , 10.7983952 ) ;
SearchResult result = service
. Get < OfficePage > ( )
. FilterGeoBoundingBox ( x => x . Location , , topLeft , bottomRight )
. GetResults ( ) ; 在給定中心點和半徑的距離內找到圓內的點。
var center = ( 59.9277542 , 10.7190847 ) ;
var radius = "10km" ;
SearchResult result = service
. Get < OfficePage > ( )
. FilterGeoDistance ( x => x . Location , radius , center )
. GetResults ( ) ; 在多邊形的多邊形內找到點。例如,多邊形可以是城市,國家或其他類型地區的輪廓。
var polygons = new [ ]
{
( 59.9702837 , 10.6149134 ) ,
( 59.9459601 , 11.0231964 ) ,
( 59.7789455 , 10.604809 )
} ;
SearchResult result = service
. Get < OfficePage > ( )
. FilterGeoPolygon ( x => x . Location , polygons )
. GetResults ( ) ;查找類似於提供的文檔ID的內容
SearchResult result = service
. MoreLikeThis ( "42" )
. GetResults ( ) ;商業:
SearchResult result = service
. MoreLikeThis ( "123__CatalogContent" )
. GetResults ( ) ;可選參數:
minimumTermFrequency最小項頻率以下是從輸入文檔中忽略條款的最低頻率。默認為1。
maxQueryTerms將選擇的最大查詢項數。提高此值可以以犧牲查詢執行速度為代價。默認為25。
minimumDocFrequency最小文檔頻率在下面將忽略輸入文檔的條款。默認為3。
minimumWordLength最小單詞長度在此將被忽略。默認為3。
小工具:

如果您不想在全球上排除類型,則只能在查詢的背景下進行:
SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. Exclude < SaladPage > ( )
. GetResults ( ) ; 在查詢時間中排除節點:
SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. Exclude ( 42 )
. Exclude ( contentInstance )
. Exclude ( contentReference )
. GetResults ( ) ;查詢使用當前CurrentCulture為默認情況。這可以覆蓋:
SearchResult result = service
. Search < ArticlePage > ( "bacon" )
. Language ( CultureInfo . GetCultureInfo ( "en" ) )
. GetResults ( ) ;使用From()和Size()的方法進行分頁,或者aliases Skip()和Take() :
SearchResult result = service
. Search < CoursePage > ( "foo" )
. From ( 10 )
. Size ( 20 )
. GetResults ( ) ; var query = service
. Search < CoursePage > ( "foo" )
. FacetsFor ( x => x . DepartmentID ) ; 方面將是從當前應用的過濾器而不是整個結果創建的。
var query = service
. Search < CoursePage > ( "foo" )
. FacetsFor ( x => x . DepartmentID , usePostFilter : false ) ; 一個值:
string selectedFilter = Request . Querstring [ "filter" ] ;
query = query . Filter ( p => p . DepartmentID , selectedFilter ) ;一個值,通過擴展方法:
string selectedFilter = Request . Querstring [ "filter" ] ;
query = query . Filter ( p => p . GetDepartmentID ( ) , selectedFilter ) ;多個值:
string [ ] selectedFilters = Request . Querstring [ "filters" ] ;
query = query . Filter ( p => p . DepartmentID , selectedFilters ) ;使用和操作員在所有過濾器上過濾:
string [ ] selectedFilters = Request . Querstring [ "filters" ] ;
query = query . Filter ( p => p . DepartmentID , selectedFilters , Operator . And ) ; SearchResult results = query . GetResults ( ) ; foreach ( FacetEntry facet in results . Facets )
{
// facet.Key = name of the property, ie. DepartmentID
// facet.Count = number of unique values for this facet
foreach ( FacetHit hit in facet . Hits )
{
// hit.Key = facet value
// hit.Count = number with this value
}
} 可以將多個過濾器分組以形成更複雜的查詢。
在下面的示例中,必須正確進行匹配:
Sizes是"xs"或"xl"
ProductCategory是"pants"
Brand要么是"levis"或"diesel"
query = query
. FilterGroup ( group => group
. Or ( page => page . Sizes ( ) , new [ ] { "xs" , "xl" } )
. And ( page => page . ProductCategory , "pants" )
. Or ( page => page . Brand , new [ ] { "levis" , "diesel" } )
) ; 要過濾某些值,請使用FilterMustNot
var query = service
. Search < PageData > ( "foo" )
. FilterMustNot ( x => x . Title , "bar" ) ;要過濾當前用戶ACL,請使用FilterByACL
var query = service
. Search < PageData > ( "foo" )
. FilterByACL ( ) ;默認情況下將使用EPiServer.Security.PrincipalInfo.Current ,但可以在需要時提供自定義的PrincipalInfo 。
要在給定的值範圍內搜索,請使用Range函數。
受支持的類型是DateTime , double , decimal和long (包括int , byte等的隱式轉換等)
SearchResult result = service
. Search ( "bacon" )
. Range ( x => x . StartPublish , DateTime . Now . Date , DateTime . Now . Date . AddDays ( 2 ) )
. GetResults ( ) ; SearchResult result = service
. Search ( "bacon" )
. Range ( x => x . MyNumber , 10 , 20 )
. GetResults ( ) ;不太可能的論點是可選的。
SearchResult result = service
. Search ( "bacon" )
. Range ( x => x . MyNumber , 10 ) // Returns anything above 10
. GetResults ( ) ;要在另一個間隔內搜索一個間隔,您的屬性必須是類型Epinova.ElasticSearch.Core.Models.Properties.IntegerRange 。
當前int是唯一受支持的類型。
SearchResult result = service
. Search ( "bacon" )
. Range ( x => x . MyRange , 10 , 20 )
. GetResults ( ) ; public class ArticlePage : StandardPage
{
[Display]
public virtual int From { get; set; }
[Display]
public virtual int To { get; set; }
public IntegerRange MyRange => new IntegerRange(From, To);
}
如果屬性是類型的IDictionary<string, object>和標記[Searchable] ,則將其索引為Elasticsearch中的object 。
這在您具有動態鍵值數據的情況下很有用,這些數據必須像PIM系統一樣。
標準財產方法:
public class ProductPage
{
[Searchable]
public IDictionary<string, object> Metadata { get; set; }
}
數據本身不會返回,但是您可以查詢並製作方面:
SearchResult result = service
. Search < ProductPage > ( "bacon" )
. InField ( x => x . Metadata + ".SomeKey" )
. FacetsFor ( x => x . Metadata + ".SomeKey" )
. GetResults ( ) ;自定義屬性:
public static class SearchConfig
{
public static void Init ( )
{
Epinova . ElasticSearch . Core . Conventions . Indexing . Instance
. ForType < ProductPage > ( ) . IncludeField ( "Metadata" , x => x . GetPimDataDictionary ( ) ) ;
}
}此方法返回數據:
SearchResult result = service
. Search < ProductPage > ( "bacon" )
. GetResults ( ) ;
var hit = result . Hits . First ( ) ;
var dict = hit . Custom [ "Metadata" ] as IDictionary < string , object >可以通過用Boost屬性裝飾屬性來提高屬性:
[ Boost ( 13 ) ]
public string Title { get ; set ; }…或查詢時間:
SearchResult result = service
. Search ( "bacon" )
. Boost ( x => x . MyProp , 3 )
. GetResults ( ) ;可以給出一種正或負增長:
SearchResult result = service
. Search ( "bacon" )
. Boost < ArticlePage > ( 2 )
. GetResults ( ) ; SearchResult result = service
. Search ( "bacon" )
. Boost ( typeof ( ArticlePage ) , 2 )
. GetResults ( ) ; SearchResult result = service
. Search ( "bacon" )
. Boost < ArticlePage > ( - 3 )
. GetResults ( ) ;您還可以根據其在頁面樹中的位置來提高命中:
SearchResult result = service
. Search ( "bacon" )
. BoostByAncestor ( new ContentReference ( 42 ) , 2 )
. GetResults ( ) ;通過使用Decay功能,可以根據其值評分日期屬性。這樣,您可以將較新的文章推廣到較舊的文章中。
SearchResult result = service
. Search ( "bacon" )
. Decay ( x => x . StartPublish , TimeSpan . FromDays ( 7 ) )
. GetResults ( ) ;每次發生日期間隔(第二參數)時,從分數中減去0.5點。在上面的示例中,7天后,14天后1點等於0.5點,依此類推。
在查詢上使用.UseBestBets()以高於正常水平評分所選內容。
SearchResult result = service
. Search ( "bacon" )
. UseBestBets ( )
. GetResults ( ) ;最佳選擇可以通過嵌入式菜單搜索引擎 - >最佳選擇來管理。

可以使用.Track()函數收集簡單統計信息。這將跟踪查詢該術語的次數以及是否返回任何命中。
SearchResult result = service
. Search ( "bacon" )
. Track ( )
. GetResults ( ) ; 
注意:如果您的連接字符串未命名EPiServerDB則必須在trackingConnectionStringName -Configuration中提供其名稱,請參見安裝
默認情況下,Stemming應用於XhtmlString類型的所有屬性,或稱為MainIntro或MainBody屬性。
該語言基於內容語言。類型string的其他屬性可以通過Stem - 屬性裝飾它們來阻止它們:
[ Stem ]
public string Title { get ; set ; }要列出某種類型的內容,而無需進行任何評分或分析,請使用Get函數。這可以與SortBy一起用於簡單列表。
SearchResult result = service
. StartFrom ( somePageLink )
. Get < ArticlePage > ( )
. GetResults ( ) ;排序通常由Elasticsearch根據每場比賽的分數執行。手動排序僅在評分無關的方案中使用,例如使用前面提到的Get功能時。
SearchResult result = service
. Get < ArticlePage > ( )
. SortBy ( p => p . StartPublish )
. ThenBy ( p => p . Foo )
. ThenBy ( p => p . Bar )
. GetResults ( ) ; 當對地理點進行排序時,還有一個強制性的論點。 compareTo 。將將項目與這些坐標進行比較,並將結果距離用作排序值。
對於絕對控制,您可以使用腳本對文檔進行排序。請注意,這可能會影響性能。
基於某個時間戳的示例排序:
var timestamp = new DateTimeOffset ( new DateTime ( 2019 , 1 , 1 ) ) . ToUnixTimeMilliseconds ( ) ;
var script = $ "doc['StartPublish'].date.getMillis() > { timestamp } ? 0 : 1" ;
SearchResult result = service
. Get < ArticlePage > ( )
. SortByScript ( script , true , "number" )
. GetResults ( ) ;請參閱https://www.elastic.co/guide/en/elasticsearch/painless/current/current/index.html,以進行腳本語法。
包括帶狀皰疹過濾器,在搜索拼寫錯誤的單詞時,可以建議在索引中發現類似的單詞。
所發現的任何建議都將包括在搜索結果的DidYouMean屬性中:
SearchResult result = service
. Search ( "alloi" )
. GetResults ( ) ;
string [ ] didYouMean = result . DidYouMean ; // [ "alloy", "all" ]任何應作為建議來源的屬性都必須標記為[DidYouMeanSource] 。
public class StandardPage : SitePageData
{
[ DidYouMeanSource ]
public virtual XhtmlString MainBody { get ; set ; }
} GetResults()返回的結果不知道Episerver。在情節上下文中使用函數GetContentResults() 。
這將自動應用過濾器FilterAccess , FilterPublished和FilterTemplate 。
IEnumerable < IContent > content = service
. Search < CoursePage > ( text )
. GetContentResults ( ) ; 如果在編輯模式下搜索時要使用任何隨附的提供商,請轉到CMS-> Admin-> config-> contig-> tool設置 - >搜索配置。
勾選提供商並將其拖到列表的頂部。
同義詞可以從菜單搜索引擎 - >同義詞中管理。
在執行通用操作(例如發布,移動和刪除)時,內容將自動重新索引。
要對所有內容進行初始索引,請運行計劃的任務«elasticsearch:index cms content»
重新索引也可以通過工具 - 菜單手動觸發個人內容:

…或通過頁面樹中的上下文菜單:

GetResults()返回的結果不知道Episerver。在情節貿易貿易上使用函數GetCatalogResults() 。這將自動選擇正確的索引,並應用FilterAccess器, FilterPublished和FilterTemplate 。
IEnumerable < ProductContent > content = service
. Search < ProductContent > ( text )
. GetCatalogResults ( ) ; 在執行通用操作(例如發布,移動和刪除)時,內容將自動重新索引。
要對所有內容進行初始索引,請運行計劃的任務«Elasticsearch:Index Commerce Content»
您可以通過菜單搜索引擎 - >管理和狀態,可以在普通和三克令牌之間切換(硬編碼為最小= 3,max = 3,max = 3,tokens = Digit,char,char,char,char,char,char,char,char)。
使用Highlight()函數從文本中的匹配中獲取150個字符的摘錄。
SearchResult result = service
. Search ( "bacon" )
. Highlight ( )
. GetContentResults ( ) ;默認情況下,突出顯示了名為MainIntro , MainBody , Attachment和Description屬性。
默認標記為<mark>
您可以使用以下配置選項自定義此行為:
Indexing . Instance . ForType < ArticlePage > ( ) . EnableHighlighting ( x => x . MyField ) ;
Indexing . Instance . SetHighlightFragmentSize ( 42 ) ;
Indexing . Instance . SetHighlightTag ( "blink" ) ;結果可以在每個命中的Highlight屬性中找到。
使用Bulk函數索引自定義內容。
例子:
var obj1 = new ComplexType { StringProperty = "this is myobj 1" } ;
var obj2 = new ComplexType { StringProperty = "this is myobj 2" } ;
var obj3 = new ComplexType { StringProperty = "this is myobj 3" } ;
ICoreIndexer indexer = ServiceLocator . Current . GetInstance < ICoreIndexer > ( ) ; // Can also be injected
BulkBatchResult bulk = indexer . Bulk ( new [ ]
{
new BulkOperation ( obj1 , "no" ) ,
new BulkOperation ( obj2 , "no" ) ,
new BulkOperation ( obj3 , "no" )
} ) ;
var results = _service
. Search < ComplexType > ( "myobj" )
. InField ( x => x . StringProperty )
. GetCustomResults ( ) ; 如果您喜歡避免碰撞的自定義索引,則必須在索引和搜索時提供此信息:
var obj1 = new ComplexType { StringProperty = "this is myobj 1" } ;
var obj2 = new ComplexType { StringProperty = "this is myobj 2" } ;
var obj3 = new ComplexType { StringProperty = "this is myobj 3" } ;
ICoreIndexer indexer = ServiceLocator . Current . GetInstance < ICoreIndexer > ( ) ; // Can also be injected
string indexName = "my-uber-custom-name-no" ;
BulkBatchResult bulk = indexer . Bulk ( new [ ]
{
new BulkOperation ( obj1 , "no" , index : indexName ) ,
new BulkOperation ( obj2 , "no" , index : indexName ) ,
new BulkOperation ( obj3 , "no" , index : indexName )
} ) ;
var results = _service
. UseIndex ( indexName )
. Search < ComplexType > ( "myobj" )
. InField ( x => x . StringProperty )
. GetCustomResults ( ) ; epinova.elasticsearch使用標準HttpClient來調用elasticsearch。有時,處理髮送的消息是必要的。例如簽署雲服務請求。
如果您想要幾個httpmessagehandlers,我們建議在設置之前將它們鏈接。
例如:
MessageHandler . Instance . SetMessageHandler ( new AWSHandler ( ) ) ; GetCustomResults返回強烈鍵入的對象,而不是GetContentResults ,而GetContentResults僅返回ID。
自定義對像不需要Id屬性(或BulkOperation CTOR中的相應參數),但是如果您需要控製版本控制和更新/刪除,建議這樣做。