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);
}
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;
}
}