Anyone? I also noticed this method for searching for files, see code below.
http://world.episerver.com/Documentation/Class-library/?documentId=cms/7/c6827903-02d8-c5f4-cdc0-7e6ba478f9d8
But since the images etc. are resided in SiteDefinition.Current.GlobalAssetsRoot which is a ContentReference, I'm not sure how to use this method since searchRoot is of type VersioningDirectory. I tried rewriting it to use "AddContentNodes" instead of "AddDirectoryNodes" and passing in GlobalAssetsRoot, but without success.
I would really appreciate some help with this, have a nice weekend!
public IEnumerable<string> FindFiles(string searchQuery, VersioningDirectory searchRoot, int pagingNumber, int pagingSize) { // The group query is needed to combine the different criteria GroupQuery groupQuery = new GroupQuery(LuceneOperator.AND); // The unified file query makes sure we only get hits that are files groupQuery.QueryExpressions.Add(new UnifiedFileQuery()); // The field query contains the search phrase groupQuery.QueryExpressions.Add(new FieldQuery(searchQuery)); // The virtual path query makes sure that we only get hits for children of the specified search root VirtualPathQuery pathQuery = new VirtualPathQuery(); pathQuery.AddDirectoryNodes(searchRoot); groupQuery.QueryExpressions.Add(pathQuery); // The access control list query will remove any files the user doesn't have read access to AccessControlListQuery aclQuery = new AccessControlListQuery(); aclQuery.AddAclForUser(PrincipalInfo.Current, HttpContext.Current); groupQuery.QueryExpressions.Add(aclQuery); SearchResults results = Locate.SearchHandler().GetSearchResults(groupQuery, pagingNumber, pagingSize); foreach (var hit in results.IndexResponseItems) { // Return the virtual path for each matching file. yield return hit.Uri.ToString(); } }
Hi! My solution was to do one search for media and one for pages and then combine them using AddRange. Pasted all code below, it's a bit extensive but if you start looking in the method Search in PageSearchService, there is the method you would call from your SearchPageController or similar, and there you can see the combining of the two searches and the underlying logic.
public class SearchService { private readonly SearchHandler _searchHandler; private readonly IContentLoader _contentLoader; public SearchService(SearchHandler searchHandler, IContentLoader contentLoader) { _searchHandler = searchHandler; _contentLoader = contentLoader; } public virtual bool IsActive { get { return SearchSettings.Config.Active; } } public virtual SearchResults SearchForContent(string searchText, IEnumerable<ContentReference> contentSearchRoots, HttpContextBase context, string languageBranch, int maxResults) { var query = CreateContentQuery(searchText, contentSearchRoots, context, languageBranch); return _searchHandler.GetSearchResults(query, 1, maxResults); } private IQueryExpression CreateContentQuery(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch) { var query = new GroupQuery(LuceneOperator.AND); float x = 0.5f; query.QueryExpressions.Add(new FuzzyQuery(searchText, x)); //Create and add query which groups type conditions using OR var typeQueries = new GroupQuery(LuceneOperator.OR); query.QueryExpressions.Add(typeQueries); foreach (var root in searchRoots) { var contentRootQuery = new VirtualPathQuery(); contentRootQuery.AddContentNodes(root, _contentLoader); typeQueries.QueryExpressions.Add(contentRootQuery); } var accessRightsQuery = new AccessControlListQuery(); accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context); query.QueryExpressions.Add(accessRightsQuery); return query; } public virtual SearchResults SearchForPages(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch, int maxResults) { var query = CreatePageQuery(searchText, searchRoots, context, languageBranch); return _searchHandler.GetSearchResults(query, 1, maxResults); } private IQueryExpression CreatePageQuery(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch) { //Main query which groups other queries. Each query added //must match in order for a page or file to be returned. var query = new GroupQuery(LuceneOperator.AND); //Add free text query to the main query query.QueryExpressions.Add(new FieldQuery(searchText)); //Search for pages using the provided language var pageTypeQuery = new GroupQuery(LuceneOperator.AND); pageTypeQuery.QueryExpressions.Add(new ContentQuery<PageData>()); pageTypeQuery.QueryExpressions.Add(new FieldQuery(languageBranch, Field.Culture)); //Search for media without languages var contentTypeQuery = new GroupQuery(LuceneOperator.OR); contentTypeQuery.QueryExpressions.Add(new ContentQuery<MediaData>()); contentTypeQuery.QueryExpressions.Add(pageTypeQuery); query.QueryExpressions.Add(contentTypeQuery); //Create and add query which groups type conditions using OR var typeQueries = new GroupQuery(LuceneOperator.OR); query.QueryExpressions.Add(typeQueries); foreach (var root in searchRoots) { var contentRootQuery = new VirtualPathQuery(); contentRootQuery.AddContentNodes(root, _contentLoader); typeQueries.QueryExpressions.Add(contentRootQuery); } var accessRightsQuery = new AccessControlListQuery(); accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context); query.QueryExpressions.Add(accessRightsQuery); return query; } }
public class PagesSearchService { private readonly SearchService _searchService; private readonly ContentSearchHandler _contentSearchHandler; private readonly UrlResolver _urlResolver; private readonly TemplateResolver _templateResolver; public PagesSearchService(SearchService searchService, ContentSearchHandler contentSearchHandler, TemplateResolver templateResolver, UrlResolver urlResolver) { _searchService = searchService; _contentSearchHandler = contentSearchHandler; _templateResolver = templateResolver; _urlResolver = urlResolver; } /// <summary> /// Performs a search for pages and media and maps each result to the view model class SearchHit. /// </summary> /// <remarks> /// The search functionality is handled by the injected SearchService in order to keep the controller simple. /// Uses EPiServer Search. For more advanced search functionality such as keyword highlighting, /// facets and search statistics consider using EPiServer Find. /// </remarks> public IEnumerable<SearchPageViewModel.SearchHit> Search(string searchText, IEnumerable<ContentReference> searchRoots, IEnumerable<ContentReference> contentSearchRoots, HttpContextBase context, string languageBranch, int maxHits) { var pageSearchResults = _searchService.SearchForPages(searchText, searchRoots, context, languageBranch, maxHits); var contentSearchResults = _searchService.SearchForContent(searchText, contentSearchRoots, context, languageBranch, maxHits); pageSearchResults.IndexResponseItems.AddRange(contentSearchResults.IndexResponseItems); return pageSearchResults.IndexResponseItems.GroupBy(p => p.DisplayText).Select(g => g.First()).SelectMany(CreateHitModel); } private IEnumerable<SearchPageViewModel.SearchHit> CreateHitModel(IndexResponseItem responseItem) { var content = _contentSearchHandler.GetContent<IContent>(responseItem); if (content != null) { if (content is ArticleBasePage || content is MediaData) { yield return CreatePageHit(content, responseItem); } } } private bool HasTemplate(IContent content) { return _templateResolver.HasTemplate(content, TemplateTypeCategories.Page); } private bool IsPublished(IVersionable content) { if (content == null) return true; return content.Status.HasFlag(VersionStatus.Published); } private SearchPageViewModel.SearchHit CreatePageHit(IContent content, IndexResponseItem item) { var contentPage = content as ContentPage; var mediaData = content as MediaData; if (contentPage != null) { return GetContentPageSearchHit(item, contentPage); } else if (mediaData != null) { return GetMediaDataSearchHit(item, mediaData); } return null; } private SearchPageViewModel.SearchHit GetContentPageSearchHit(IndexResponseItem item, ContentPage contentPage) { return new SearchPageViewModel.SearchHit { Title = (contentPage != null ? contentPage.Heading : item.Title), Url = (contentPage != null ? _urlResolver.GetUrl(contentPage.ContentLink) : ""), Excerpt = item.DisplayText, PageLink = (contentPage != null ? contentPage.ContentLink.ToPageReference() : null), PublishDate = contentPage != null ? contentPage.StartPublish : DateTime.MinValue }; } private SearchPageViewModel.SearchHit GetMediaDataSearchHit(IndexResponseItem item, MediaData mediaData) { var mmxImage = mediaData as MMXImageFile; string excerptText = ""; if (mmxImage != null) { excerptText = GetMmxImageExcerptText(mmxImage); } if (string.IsNullOrEmpty(excerptText)) excerptText = item.DisplayText; return new SearchPageViewModel.SearchHit { Title = item.Title, Url = _urlResolver.GetUrl(mediaData.ContentLink), Excerpt = excerptText, PageLink = mediaData.ContentLink.ToPageReference(), PublishDate = mediaData.StartPublish ?? DateTime.MinValue }; } private string GetMmxImageExcerptText(MMXImageFile image) { StringBuilder excerpt = new StringBuilder(); if (!string.IsNullOrEmpty(image.Title)) excerpt.Append(image.Title); if (!string.IsNullOrEmpty(image.Title) && !string.IsNullOrEmpty(image.AlternativeText)) excerpt.Append(". "); if (!string.IsNullOrEmpty(image.AlternativeText)) excerpt.Append(image.AlternativeText); return excerpt.ToString(); } public bool IsSearchActive { get { return _searchService.IsActive; } } }
[Pasting files is not allowed]
Hello! I'm implementing a serch page which is using EpiServer Search, for creating the search result I'm using the CreateQuery method from the Alloy-project. This works fine when searching for pages, but when I'm searching for an image I get no hits at all.
Our image-class is inheriting from MedaData, so I don't get why we don't get any hits. But, If I change,
to LuceneOperator.OR and search for an image all the images from the site are displayed in the search result. So, I at least know that they ar indexed.
How can I change this code so that I can search for both pages and files?
These are the searchRoots that I use as argument:
CreateQuery-method: