private IEnumerable <Document> GetRelatedAnnotations(RawSearchResultSet rawSearchResults, ICrmEntityQuery query) { Query textQuery; var noteQuery = new BooleanQuery(); var queryParser = new QueryParser(Index.Version, Index.ContentFieldName, Index.GetQuerySpecificAnalyzer(query.MultiLanguageEnabled, query.ContextLanguage)); try { textQuery = queryParser.Parse(string.Format("+({0}) filename:({0}) notetext:({0}) _logicalname:annotation~0.9^0.3", query.QueryTerm)); } catch (ParseException) { textQuery = queryParser.Parse(QueryParser.Escape(string.Format("+({0}) filename:({0}) notetext:({0}) _logicalname:annotation~0.9^0.3", query.QueryTerm))); } noteQuery.Add(textQuery, Occur.MUST); noteQuery.Add(new TermQuery(new Term("_logicalname", "annotation")), Occur.MUST); foreach (var scoreDoc in rawSearchResults.Results) { var resultField = _searcher.Doc(scoreDoc.Doc).GetField("_logicalname"); if (resultField != null && resultField.StringValue == "knowledgearticle") { var primaryKey = _searcher.Doc(scoreDoc.Doc).GetField("_primarykey"); noteQuery.Add(new TermQuery(new Term("annotation_knowledgearticleid", primaryKey.StringValue)), Occur.SHOULD); } } var rawNoteResults = GetRawSearchResults(noteQuery, 30, 0); return(rawNoteResults.Results.Select(rawNoteResult => _searcher.Doc(rawNoteResult.Doc)).ToList()); }
/// <summary> /// Override to return facets and sorting options. /// </summary> /// <param name="results">Search results to display to user.</param> /// <param name="approximateTotalHits">Estimate of the number of results.</param> /// <param name="pageNumber">The page number.</param> /// <param name="pageSize">The Page size.</param> /// <param name="rawSearchResultSet">The raw search result set, which contains the raw results and other search related info.</param> /// <returns>The result page to return to the user.</returns> protected override ICrmEntitySearchResultPage GenerateResultPage(ICollection <ICrmEntitySearchResult> results, int approximateTotalHits, int pageNumber, int pageSize, RawSearchResultSet rawSearchResultSet) { var resultOffset = (pageNumber - 1) * pageSize; var pageResults = results.Skip(resultOffset).Take(pageSize).ToList(); return(new CrmEntitySearchResultPage(pageResults, approximateTotalHits, pageNumber, pageSize, rawSearchResultSet.FacetViews, rawSearchResultSet.SortingOptions)); }
/// <summary> /// Get the processed search results provided by the query available to the searching user. /// </summary> /// <param name="query">Search query.</param> /// <param name="searchLimit">Number of results to obtain from the underlying search library.</param> /// <param name="initialOffset">Number of already processed results to skip.</param> /// <param name="resultLimit">Number of results to return in the result page.</param> /// <param name="resultFactory">Factory to generate the ICrmEntitySearchResults</param> /// <param name="pageNumber">Page number</param> /// <param name="pageSize">Page size</param> /// <param name="results">Processed results so far.</param> /// <returns></returns> protected ICrmEntitySearchResultPage GetUserSearchResults(ICrmEntityQuery query, int searchLimit, int initialOffset, int resultLimit, ICrmEntitySearchResultFactory resultFactory, int pageNumber, int pageSize, ICollection <ICrmEntitySearchResult> results) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("(searchLimit={0},rawOffset={1},resultLimit={2})", searchLimit, initialOffset, resultLimit)); RawSearchResultSet rawSearchResults = GetRawSearchResults(query, searchLimit, initialOffset); if (initialOffset >= rawSearchResults.TotalHits) { return(GenerateResultPage(results, rawSearchResults.TotalHits, pageNumber, pageSize, rawSearchResults)); } var stopwatch = new Stopwatch(); stopwatch.Start(); var groupedNotes = new List <IGrouping <EntityReference, ICrmEntitySearchResult> >(); var displayNotes = IsAnnotationSearchEnabled(); if (displayNotes && !string.IsNullOrEmpty(query.QueryTerm)) { var rawNotes = this.GetRelatedAnnotations(rawSearchResults, query); var notes = rawNotes.Select(document => resultFactory.GetResult(document, 1, results.Count + 1)).ToList(); //Grouping Notes by related Knowledge Articles groupedNotes = notes.Where(note => note.EntityLogicalName == "annotation") .GroupBy(note => note.Entity.GetAttributeValue <EntityReference>("objectid")) .ToList(); } var offsetForNextIteration = initialOffset; foreach (var scoreDoc in rawSearchResults.Results) { offsetForNextIteration++; var result = resultFactory.GetResult(_searcher.Doc(scoreDoc.Doc), scoreDoc.Score, results.Count + 1); // Not a valid user result, filter out if (result == null) { continue; } if (result.EntityLogicalName == "knowledgearticle" && displayNotes) { var relatedNotes = groupedNotes.Where(a => a.Key.Id == result.EntityID).SelectMany(i => i).Take(3).ToList(); if (relatedNotes.Any(note => note.Fragment == result.Fragment)) { result.Fragment = GetKnowledgeArticleDescription(result); } result.Entity["relatedNotes"] = relatedNotes; } results.Add(result); if (results.Count >= resultLimit) { stopwatch.Stop(); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Gathered {0} results, done ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); PortalFeatureTrace.TraceInstance.LogSearch(FeatureTraceCategory.Search, results.Count, stopwatch.ElapsedMilliseconds, string.Format("Gathered {0} results, done ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); return(GenerateResultPage(results, rawSearchResults.TotalHits, pageNumber, pageSize, rawSearchResults)); } } stopwatch.Stop(); // We asked for more hits than we got back from Lucene, and we still didn't gather enough valid // results. That's all we're going to get, so the number of results we got is the number of hits. if (searchLimit >= rawSearchResults.TotalHits) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("All available results ({0}) gathered, done ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); PortalFeatureTrace.TraceInstance.LogSearch(FeatureTraceCategory.Search, results.Count, stopwatch.ElapsedMilliseconds, string.Format("All available results ({0}) gathered, done ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); return(GenerateResultPage(results, results.Count, pageNumber, pageSize, rawSearchResults)); } ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("{0} results gathered so far ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); PortalFeatureTrace.TraceInstance.LogSearch(FeatureTraceCategory.Search, results.Count, stopwatch.ElapsedMilliseconds, string.Format("{0} results gathered so far ({1}ms)", results.Count, stopwatch.ElapsedMilliseconds)); return(GetUserSearchResults(query, searchLimit * ExtendedSearchLimitMultiple, offsetForNextIteration, resultLimit, resultFactory, pageNumber, pageSize, results)); }
/// <summary> /// Creates a result page based off the processed search results. /// </summary> /// <param name="results">Search results to display to user.</param> /// <param name="approximateTotalHits">Estimate of the number of results.</param> /// <param name="pageNumber">The page number.</param> /// <param name="pageSize">The Page size.</param> /// <param name="rawSearchResultSet">The raw search result set, which contains the raw results and other search related info.</param> /// <returns>The result page to return to the user.</returns> protected virtual ICrmEntitySearchResultPage GenerateResultPage(ICollection <ICrmEntitySearchResult> results, int approximateTotalHits, int pageNumber, int pageSize, RawSearchResultSet rawSearchResultSet) { var resultOffset = (pageNumber - 1) * pageSize; var pageResults = results.Skip(resultOffset).Take(pageSize).ToList(); return(new CrmEntitySearchResultPage(pageResults, approximateTotalHits, pageNumber, pageSize)); }