Search code examples
c#umbracoexamine

Umbraco 10 Examine search, to return matches found in page titles and content


I'm trying to build a search to return both matching page titles and matching content from within content pages.

I have included the code from here to index blocklist content as well. I can find matching page titles no problem but no matter what I try I can't get it to find anything within page content.

Can anyone post a link to an example that works?

At the moment I'm working with this:

public IEnumerable<ResultItem?> SearchUmbraco(string searchTerm, int websiteId)
        {
              var examineSearcher = _examineManager.TryGetIndex("ExternalIndex", out var externalIndex)
                  ? externalIndex.Searcher
                  : null;

              var criteria = examineSearcher?.CreateQuery("content").GroupedOr(new[] { "nodeName", "content" }, searchTerm);

            var filter = criteria.Field("nodeName",     
            ISearchResults results = filter.Execute();

            // convert the results to a list of ResultItem objects while filtering out irrelevant results from other sites etc
            var content = results.Select(x => ConvertToResult(int.Parse(x.Id), websiteId, x.Score))
                  .Where(x => x != null)
            .ToList();

              return content.OrderByDescending(x => x.score);
        }

Solution

  • Here is the full-working code from one of my Umbraco v10 websites, for a similar search:

    public class SearchService : ISearchService
    {
        private readonly IExamineManager _examineManager;
        private readonly UmbracoHelper _umbracoHelper;
    
        public SearchService(IExamineManager examineManager, UmbracoHelper umbracoHelper)
        {
            _examineManager = examineManager;
            _umbracoHelper = umbracoHelper;
        }
        public ReadOnlyPagedCollection<SiteSearchModel> GetSearchItems(int page, string query, string filterValue, string searchPath, string noResultsMessage, int itemsPerPage)
        {
            IEnumerable<string> ids = Array.Empty<string>();
            if (!string.IsNullOrEmpty(query) && _examineManager.TryGetIndex("ExternalIndex", out IIndex index))
            {
                var textFields = new[] { "nodeName", "pageTitle", "title", "titleSecondRow", "description", "modules", "homeModules", "topInformationBox", "signpost", "summary", "threeCardDesign", "seoDescription", "mainContent", "articleDate" };
                ids = index
                .Searcher
                .CreateQuery(IndexTypes.Content).GroupedOr(textFields, query)
                .Execute()
                .OrderByDescending(x => x.Score)
                .Select(x => x.Id);
            }
    
            IList<SiteSearchModel> siteSearchAll = new List<SiteSearchModel>();
            foreach (var id in ids)
            {
                var publishedPage = _umbracoHelper.Content(id);
                if (publishedPage != null && publishedPage.HasProperty("hideFromSiteSearch") && !publishedPage.GetProperty("hideFromSiteSearch").GetValue().ToString().Equals(Boolean.TrueString))
                {
                    siteSearchAll.Add(publishedPage.ToSiteSearch());
                }
            }
    
            IList<SiteSearchModel> siteSearchNews = siteSearchAll.Where(s => s.Path.Contains(AppConstants.Search.NewsPath)).ToList();
            IList<SiteSearchModel> siteSearchCorporate = siteSearchAll.Where(s => s.Path.Contains(AppConstants.Search.CorporatePath)).ToList();
            IList<SiteSearchModel> siteSearchAirportInformation = siteSearchAll.Where(s => s.Path.Contains(AppConstants.Search.AirportInformationPath)).ToList();
    
            Dictionary<SearchFilter, int> resultCountByFilter = new Dictionary<SearchFilter, int>();
    
            resultCountByFilter.Add(SearchFilter.All, siteSearchAll.Count());
            resultCountByFilter.Add(SearchFilter.News, siteSearchNews.Count());
            resultCountByFilter.Add(SearchFilter.Corporate, siteSearchCorporate.Count());
            resultCountByFilter.Add(SearchFilter.AirportInformation, siteSearchAirportInformation.Count());
    
            IList<SiteSearchModel> siteSearchByFilter = new List<SiteSearchModel>();
            switch (filterValue)
            {
                case AppConstants.Search.AirportInformation:
                    siteSearchByFilter = siteSearchAirportInformation;
                    break;
                case AppConstants.Search.News:
                    siteSearchByFilter = siteSearchNews;
                    break;
                case AppConstants.Search.Corporate:
                    siteSearchByFilter = siteSearchCorporate;
                    break;
                default:
                    siteSearchByFilter = siteSearchAll;
                    break;
            }
    
            var totalPages = siteSearchByFilter != null && siteSearchByFilter.Any() ? (int)Math.Ceiling((double)siteSearchByFilter.Count() / itemsPerPage) : 0;
            if (page > totalPages || page <= 0)
            {
                page = 1;
            }
    
            var newsListing = new ListingModel(page, totalPages);
            return new ReadOnlyPagedCollection<SiteSearchModel>(siteSearchByFilter.Skip((page - 1) * itemsPerPage).Take(itemsPerPage).ToList(), newsListing, resultCountByFilter, query, filterValue, noResultsMessage);
        }
    }
    

    Here is the ISearchService:

    public interface ISearchService
    {
        public ReadOnlyPagedCollection<SiteSearchModel> GetSearchItems(int page, string query, string filterValue, string searchPath, string noResultsMessage, int itemsPerPage);
    }
    

    ReadOnlyPagedCollection:

    public class ReadOnlyPagedCollection<T>
    {
        public IReadOnlyList<T> Items { get; set; }
        public ListingModel Pagination { get; set; }
        public Dictionary<SearchFilter, int> ResultsCount { get; set; }
        public string Query { get; set; }
        public string FilterValue { get; set; }
        public string NoResultsMessage { get; set; }
        public ReadOnlyPagedCollection(IReadOnlyList<T> items, ListingModel pagination)
        {
            Items = items;
            Pagination = pagination;
        }
        public ReadOnlyPagedCollection(IReadOnlyList<T> items, ListingModel pagination, Dictionary<SearchFilter, int> resultsCount, string query, string filterValue, string noResultsMessage)
        {
            Items = items;
            Pagination = pagination;
            ResultsCount = resultsCount;
            Query = query;
            FilterValue = filterValue;
            NoResultsMessage = noResultsMessage;
        }
    }
    

    SiteSearchModel:

    public class SiteSearchModel
    {
        public string Path { get; set; }
        public string PageTitle { get; set; }
        public string PageSummary { get; set; }
        public SiteSearchModel(IPublishedContent page)
        {
            Path = page.Url(mode: UrlMode.Absolute);
            PageTitle = page.HasProperty("pageTitle") ? page.GetProperty("pageTitle").GetValue().ToString() : string.Empty;
            PageSummary = page.HasProperty("summary") && !string.IsNullOrEmpty(page.GetProperty("summary")?.GetValue().ToString()) ? page.GetProperty("summary").GetValue().ToString() : page.HasProperty("seoDescription") ? page.GetProperty("seoDescription").GetValue().ToString() : string.Empty;
        }
    }