/// <inheritdoc cref="ISearchStore{TDocument}.AdvancedCount" /> public long AdvancedCount(AdvancedQueryInput input) { if (input == null) { throw new ArgumentNullException("input"); } /* Requête de filtrage, qui inclus ici le filtre et le post-filtre puisqu'on ne fait pas d'aggrégations. */ var filterQuery = _builder.BuildAndQuery(GetFilterQuery(input), GetPostFilterSubQuery(input)); var hasFilter = !string.IsNullOrEmpty(filterQuery); var res = this.GetClient() .Count <TDocument>(s => { /* Index / type document. */ s .Index(_indexName) .Type(_documentTypeName); /* Critère de filtrage. */ if (hasFilter) { s.Query(q => q.QueryString(qs => qs.Query(filterQuery))); } return(s); }); res.CheckStatus("AdvancedCount"); return(res.Count); }
/// <summary> /// Obtient le nom du champ pour le groupement. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Nom du champ.</returns> private string GetGroupFieldName(AdvancedQueryInput input) { var groupFacetName = input.ApiInput.Group; /* Pas de groupement. */ if (string.IsNullOrEmpty(groupFacetName)) { return(null); } /* Recherche de la facette de groupement. */ var facetDef = input.FacetQueryDefinition.Facets.SingleOrDefault(x => x.Code == groupFacetName); if (facetDef == null) { throw new ElasticException("No facet " + groupFacetName + " to group on."); } var fieldName = facetDef.FieldName; /* Vérifie la présence du champ. */ if (!_definition.Fields.HasProperty(fieldName)) { throw new ElasticException("The Document \"" + _definition.DocumentTypeName + "\" is missing a \"" + fieldName + "\" property to group on."); } return(_definition.Fields[fieldName].FieldName); }
/// <summary> /// Obtient la liste des facettes. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Définitions de facettes.</returns> private ICollection <IFacetDefinition> GetFacetDefinitionList(AdvancedQueryInput input) { var groupFacetName = input.ApiInput.Group; var list = input.FacetQueryDefinition != null ? input.FacetQueryDefinition.Facets : new List <IFacetDefinition>(); /* Recherche de la facette de groupement. */ string groupFieldName = null; if (!string.IsNullOrEmpty(groupFacetName)) { var groupFacetDef = input.FacetQueryDefinition.Facets.SingleOrDefault(x => x.Code == groupFacetName); if (groupFacetDef == null) { throw new ElasticException("No facet \"" + groupFacetName + "\" to group on."); } groupFieldName = groupFacetDef.FieldName; } foreach (var facetDef in list) { /* Vérifie que le champ à facetter existe sur le document. */ GetHandler(facetDef).CheckFacet(facetDef); } return(list); }
/// <summary> /// Créé la requête de filtrage. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Requête de filtrage.</returns> private string GetFilterQuery(AdvancedQueryInput input) { var textSubQuery = GetTextSubQuery(input); var securitySubQuery = GetSecuritySubQuery(input); var filterSubQuery = GetFilterSubQuery(input); var monoValuedFacetsSubQuery = GetFacetSelectionSubQuery(input); return(_builder.BuildAndQuery(textSubQuery, securitySubQuery, filterSubQuery, monoValuedFacetsSubQuery)); }
/// <summary> /// Crée la sous requête pour les filtres custom. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetCustomSubQuery(AdvancedQueryInput input) { if (input.CustomQuery == null) { return(string.Empty); } return(input.CustomQuery); }
/// <inheritdoc cref="ISearchBroker{TDocument}.AdvancedCount" /> public long AdvancedCount(AdvancedQueryInput input) { StartProcess(nameof(AdvancedCount)); try { return(_broker.AdvancedCount(input)); } finally { StopProcess(); } }
/// <inheritdoc cref="ISearchBroker{TDocument}.AdvancedQuery" /> public QueryOutput <TDocument> AdvancedQuery(AdvancedQueryInput input) { StartProcess(nameof(AdvancedQuery)); try { return(_broker.AdvancedQuery(input)); } finally { StopProcess(); } }
public void Check_Group() { var facetQueryDefinition = new FacetQueryDefinition(); facetQueryDefinition.Facets.Add(new BooleanFacet { Name = GenreFacet, FieldName = GenreField }); var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = new Criteria(), Skip = 0, Top = 10, Group = GenreFacet }, FacetQueryDefinition = facetQueryDefinition }; var broker = SearchBrokerManager.GetBroker <PersonneDocument>(); var output = broker.AdvancedQuery(input); /* Total. */ Assert.AreEqual(6, output.TotalCount, "Nombre total de résultats attendu incorrect."); /* Groupes */ var groups = output.Groups; Assert.IsNotNull(groups); Assert.AreEqual(3, groups.Count, "Nombre de groupes attendu incorrect."); foreach (var group in groups) { var bucket = group.Value; switch (group.Key) { case "M": Assert.AreEqual(3, bucket.Count); break; case "F": Assert.AreEqual(2, bucket.Count); break; case FacetConst.NullValue: Assert.AreEqual(1, bucket.Count); break; default: Assert.Fail("Clée inattendue : " + group.Key); break; } } }
/// <summary> /// Crée la sous requête pour les champs de filtre. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetFilterSubQuery(AdvancedQueryInput input) { if (input.FilterList == null || !input.FilterList.Any()) { return(string.Empty); } var filterList = new List <string>(); foreach (KeyValuePair <string, string> entry in input.FilterList) { var field = _definition.Fields[entry.Key].FieldName; filterList.Add(_builder.BuildFilter(field, entry.Value)); } return(_builder.BuildAndQuery(filterList.ToArray())); }
/// <inheritdoc cref="ISearchBroker{TDocument}.Query" /> public IEnumerable <TDocument> Query(string text, string security = null) { if (string.IsNullOrEmpty(text)) { return(new List <TDocument>()); } var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = text, Skip = 0, Top = QueryDefaultSize }, Security = security }; var output = _store.AdvancedQuery(input); return(output.List); }
/// <summary> /// Créé la sous-requête le filtrage par sélection de facette. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetFacetSelectionSubQuery(AdvancedQueryInput input) { var facetList = input.ApiInput.Facets; if (facetList == null || !facetList.Any()) { return(string.Empty); } var facetSubQueryList = facetList.Select(f => { /* Récupère la définition de la facette. */ var def = input.FacetQueryDefinition.Facets.Single(x => x.Name == f.Key); /* Créé une sous-requête par facette. */ string s = f.Value; return(_handler.CreateFacetSubQuery(s, def)); }).ToArray(); /* Concatène en "ET" toutes les sous-requêtes. */ return(_builder.BuildAndQuery(facetSubQueryList)); }
/// <summary> /// Créé la sous-requête pour le champ textuel. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetTextSubQuery(AdvancedQueryInput input) { var value = input.ApiInput.Criteria; /* Absence de texte ou joker : sous-requête vide. */ if (string.IsNullOrEmpty(value) || value == "*") { return(string.Empty); } /* Vérifie la présence d'un champ textuel. */ var fieldDesc = _definition.TextField; if (fieldDesc == null) { throw new ElasticException("The Document \"" + _definition.DocumentTypeName + "\" needs a Search category field to allow Query."); } /* Constuit la sous requête. */ return(_builder.BuildFullTextSearch(fieldDesc.FieldName, value)); }
/// <summary> /// Créé la sous-requête le filtrage de sécurité. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetSecuritySubQuery(AdvancedQueryInput input) { var value = input.Security; /* Absence de filtrage de sécurité : sous-requêt vide. */ if (string.IsNullOrEmpty(value)) { return(string.Empty); } /* Vérifie la présence d'un champ de sécurité. */ var fieldDesc = _definition.SecurityField; if (fieldDesc == null) { throw new ElasticException("The Document \"" + _definition.DocumentTypeName + "\" needs a Security category field to allow Query with security filtering."); } /* Constuit la sous requête. */ return(_builder.BuildInclusiveInclude(fieldDesc.FieldName, value)); }
private static QueryOutput <PersonneDocument> CheckFacets(FacetListInput facetsInput, string query = null) { var facetQueryDefinition = new FacetQueryDefinition(new BooleanFacet { Name = GenreFacet, FieldName = GenreField }); var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = new Criteria { Query = query }, Skip = 0, Top = 10, Facets = facetsInput, }, FacetQueryDefinition = facetQueryDefinition }; var broker = SearchBrokerManager.GetBroker <PersonneDocument>(); return(broker.AdvancedQuery(input)); }
/// <summary> /// Obtient la définition du tri. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Définition du tri.</returns> private SortDefinition GetSortDefinition(AdvancedQueryInput input) { var fieldName = input.ApiInput.SortFieldName; /* Cas de l'absence de tri. */ if (string.IsNullOrEmpty(fieldName)) { return(new SortDefinition()); } /* Vérifie la présence du champ. */ if (!_definition.Fields.HasProperty(fieldName)) { throw new ElasticException("The Document \"" + _definition.DocumentTypeName + "\" is missing a \"" + fieldName + "\" property to sort on."); } return(new SortDefinition { FieldName = _definition.Fields[fieldName].FieldName, Order = input.ApiInput.SortDesc ? SortOrder.Descending : SortOrder.Ascending }); }
private static void CheckFacets(long expected, FacetListInput facetsInput, string query = null) { var facetQueryDefinition = new FacetQueryDefinition(new BooleanFacet { Code = GenreFacet, FieldName = GenreField }); var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = new Criteria { Query = query }, Skip = 0, Top = 10, Facets = facetsInput, }, FacetQueryDefinition = facetQueryDefinition }; var broker = SearchBrokerManager.GetBroker <PersonneDocument>(); var actual = broker.AdvancedCount(input); Assert.AreEqual(expected, actual, "Le compte n'est pas bon."); }
private static QueryOutput <PersonneDocument> CheckFacets(FacetListInput facetsInput, string query = null, string security = null, string portfolio = null) { var facetQueryDefinition = new FacetQueryDefinition(new PortfolioFacet { Code = DepartementFacet, FieldName = DepartementField }); var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = new Criteria { Query = query }, Skip = 0, Top = 10, Facets = facetsInput, }, FacetQueryDefinition = facetQueryDefinition, Security = security, Portfolio = portfolio }; var broker = SearchBrokerManager.GetBroker <PersonneDocument>(); return(broker.AdvancedQuery(input)); }
private static void Check_Sort(bool sortDescending, IEnumerable <string> expectedNomList) { var input = new AdvancedQueryInput { ApiInput = new QueryInput { Criteria = new Criteria(), Skip = 0, Top = 10, SortFieldName = "NomSort", SortDescending = sortDescending } }; var broker = SearchBrokerManager.GetBroker <PersonneDocument>(); var output = broker.AdvancedQuery(input); /* Total. */ Assert.AreEqual(6, output.List.Count, "Nombre de résultats attendu incorrect."); Assert.AreEqual(6, output.TotalCount, "Nombre total de résultats attendu incorrect."); var nomList = output.List.Select(x => x.Nom); Assert.IsTrue( Enumerable.SequenceEqual(expectedNomList, nomList), "Tri attendu : " + string.Join(",", expectedNomList) + Environment.NewLine + " | Tri constaté : " + string.Join(",", nomList)); }
/// <summary> /// Créé la sous-requête de post-filtrage pour les facettes multi-sélectionnables. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetPostFilterSubQuery(AdvancedQueryInput input) { var facetList = input.ApiInput.Facets; if (facetList == null || !facetList.Any()) { return(string.Empty); } /* Créé une sous-requête par facette */ var facetSubQueryList = facetList .Select(f => { /* Récupère la définition de la facette multi-sélectionnable. */ var def = input.FacetQueryDefinition.Facets.SingleOrDefault(x => x.IsMultiSelectable == true && x.Code == f.Key); if (def == null) { return(null); } var handler = GetHandler(def); /* On fait un "OR" sur toutes les valeurs sélectionnées. */ return(_builder.BuildOrQuery(f.Value.Select(s => handler.CreateFacetSubQuery(s, def, input.Portfolio)).ToArray())); }) .Where(f => f != null) .ToArray(); if (facetSubQueryList.Any()) { /* Concatène en "ET" toutes les sous-requêtes. */ return(_builder.BuildAndQuery(facetSubQueryList)); } else { return(string.Empty); } }
/// <summary> /// Créé la sous-requête le filtrage par sélection de facette non multi-sélectionnables. /// </summary> /// <param name="input">Entrée.</param> /// <returns>Sous-requête.</returns> private string GetFacetSelectionSubQuery(AdvancedQueryInput input) { var facetList = input.ApiInput.Facets; if (facetList == null || !facetList.Any()) { return(string.Empty); } /* Créé une sous-requête par facette. */ var facetSubQueryList = facetList .Select(f => { /* Récupère la définition de la facette non multi-sélectionnable. */ var def = input.FacetQueryDefinition.Facets.SingleOrDefault(x => x.IsMultiSelectable == false && x.Code == f.Key); if (def == null) { return(null); } /* La facette n'est pas multi-sélectionnable donc on prend direct la première valeur. */ var s = f.Value[0]; return(GetHandler(def).CreateFacetSubQuery(s, def, input.Portfolio)); }) .Where(f => f != null) .ToArray(); if (facetSubQueryList.Any()) { /* Concatène en "ET" toutes les sous-requêtes. */ return(_builder.BuildAndQuery(facetSubQueryList)); } else { return(string.Empty); } }
/// <inheritdoc cref="ISearchBroker{TDocument}.AdvancedQuery" /> public QueryOutput <TDocument> AdvancedQuery(AdvancedQueryInput input) { return(_store.AdvancedQuery(input)); }
/// <inheritdoc cref="ISearchBroker{TDocument}.AdvancedCount" /> public long AdvancedCount(AdvancedQueryInput input) { return(_store.AdvancedCount(input)); }
/// <inheritdoc cref="ISearchStore{TDocument}.AdvancedQuery" /> public QueryOutput <TDocument> AdvancedQuery(AdvancedQueryInput input) { if (input == null) { throw new ArgumentNullException("input"); } var apiInput = input.ApiInput; /* Tri */ var sortDef = GetSortDefinition(input); /* Requête de filtrage. */ var textSubQuery = GetTextSubQuery(input); var securitySubQuery = GetSecuritySubQuery(input); var facetSubQuery = GetFacetSelectionSubQuery(input); var filterSubQuery = GetFilterSubQuery(input); var conditionSubQuery = GetConditionSubQuery(input); var customSubQuery = GetCustomSubQuery(input); var filterQuery = _builder.BuildAndQuery(textSubQuery, securitySubQuery, facetSubQuery, filterSubQuery, conditionSubQuery, customSubQuery); var hasFilter = !string.IsNullOrEmpty(filterQuery); /* Facettage. */ var facetDefList = GetFacetDefinitionList(input); var hasFacet = facetDefList.Any(); /* Group */ var groupFieldName = GetGroupFieldName(input); var hasGroup = !string.IsNullOrEmpty(apiInput.Group); /* Pagination. */ var skip = apiInput.Skip ?? 0; var size = hasGroup ? 0 : apiInput.Top ?? 100000; // TODO Paramétrable ? var res = this.GetClient() .Search <TDocument>(s => { s /* Index / type document. */ .Index(_indexName) .Type(_documentTypeName) /* Pagination */ .From(skip) .Size(size); /* Tri */ if (sortDef.HasSort) { s.Sort(x => x .OnField(sortDef.FieldName) .Order(sortDef.Order)); } /* Critère de filtrage. */ if (hasFilter) { s.Query(q => q.QueryString(qs => qs .Query(filterQuery))); } /* Aggrégations. */ if (hasFacet || hasGroup) { s.Aggregations(a => { if (hasFacet) { /* Facettage. */ foreach (var facetDef in facetDefList) { _handler.DefineAggregation(a, facetDef); } } if (hasGroup) { /* Groupement. */ a.Terms(groupFieldName, st => st .Field(groupFieldName) .Size(10) .Aggregations(g => g .TopHits(_topHitName, x => { x.Size(10); if (sortDef.HasSort) { x.Sort(t => t .OnField(sortDef.FieldName) .Order(sortDef.Order)); } return(x); }))); /* Groupement pour les valeurs nulles */ a.Missing(groupFieldName + MissingGroupPrefix, st => st .Field(groupFieldName) .Aggregations(g => g .TopHits(_topHitName, x => x.Size(10)))); } return(a); }); } return(s); }); res.CheckStatus("AdvancedQuery"); /* Extraction des facettes. */ var facetListOutput = new List <FacetOutput>(); if (hasFacet) { var aggs = res.Aggs; foreach (var facetDef in facetDefList) { FacetOutput facetOutput = _handler.ExtractFacetOutput(aggs, facetDef); facetOutput.Code = facetDef.Name; facetOutput.Label = facetDef.Label; facetListOutput.Add(facetOutput); } } /* Ajout des facettes manquantes */ if (input.ApiInput.Facets != null) { foreach (var facet in input.ApiInput.Facets) { FacetOutput facetOutput = facetListOutput.Where(f => f.Code == facet.Key).First(); if (!facetOutput.Values.Any(f => f.Code == facet.Value)) { facetOutput.Values.Add(new Kinetix.ComponentModel.SearchV3.FacetItem { Code = facet.Value, Label = facetDefList.FirstOrDefault(fct => fct.Name == facet.Key)?.ResolveLabel(facet.Value), Count = 0 }); } } } /* Extraction des résultats. */ var resultList = new List <TDocument>(); var groupResultList = new List <GroupResult <TDocument> >(); if (hasGroup) { /* Groupement. */ var bucket = (Bucket)res.Aggregations[groupFieldName]; foreach (KeyItem group in bucket.Items) { var groupName = group.Key; var topHitAgg = (TopHitsMetric)group.Aggregations[_topHitName]; var docs = topHitAgg.Documents <TDocument>().ToList(); groupResultList.Add(new GroupResult <TDocument>() { Code = groupName, Label = facetDefList.FirstOrDefault(fct => fct.Name == apiInput.Group)?.ResolveLabel(groupName), List = docs }); } /* Groupe pour les valeurs null. */ var nullBucket = (SingleBucket)res.Aggregations[groupFieldName + MissingGroupPrefix]; var nullTopHitAgg = (TopHitsMetric)nullBucket.Aggregations[_topHitName]; var nullDocs = nullTopHitAgg.Documents <TDocument>().ToList(); if (nullDocs.Any()) { groupResultList.Add(new GroupResult <TDocument>() { Code = FacetConst.NullValue, List = nullDocs }); } resultList = null; } else { /* Liste unique. */ resultList = res.Documents.ToList(); groupResultList = null; } /* Construction de la sortie. */ var output = new QueryOutput <TDocument> { List = resultList, Facets = facetListOutput, Groups = groupResultList, Query = apiInput, TotalCount = res.Total }; return(output); }
/// <inheritdoc cref="ISearchStore{TDocument}.AdvancedQuery" /> public QueryOutput <TDocument> AdvancedQuery(AdvancedQueryInput input) { if (input == null) { throw new ArgumentNullException("input"); } var apiInput = input.ApiInput; /* Tri */ var sortDef = GetSortDefinition(input); /* Requêtes de filtrage. */ var filterQuery = GetFilterQuery(input); var hasFilter = !string.IsNullOrEmpty(filterQuery); var postFilterQuery = GetPostFilterSubQuery(input); var hasPostFilter = !string.IsNullOrEmpty(postFilterQuery); /* Facettage. */ var facetDefList = GetFacetDefinitionList(input); var hasFacet = facetDefList.Any(); var portfolio = input.Portfolio; /* Group */ var groupFieldName = GetGroupFieldName(input); var hasGroup = !string.IsNullOrEmpty(apiInput.Group); /* Pagination. */ var skip = apiInput.Skip ?? 0; var size = hasGroup ? 0 : apiInput.Top ?? 1000; // TODO Paramétrable ? var res = this.GetClient() .Search <TDocument>(s => { s /* Index / type document. */ .Index(_indexName) .Type(_documentTypeName) /* Pagination */ .From(skip) .Size(size); /* Tri */ if (sortDef.HasSort) { s.Sort(x => x .Field(sortDef.FieldName, sortDef.Order)); } /* Critère de filtrage. */ if (hasFilter) { s.Query(q => q.QueryString(qs => qs.Query(filterQuery))); } /* Critère de post-filtrage. */ if (hasPostFilter) { s.PostFilter(q => q.QueryString(qs => qs.Query(postFilterQuery))); } /* Aggrégations. */ if (hasFacet || hasGroup) { s.Aggregations(a => { if (hasFacet) { /* Facettage. */ foreach (var facetDef in facetDefList) { GetHandler(facetDef).DefineAggregation(a, facetDef, facetDefList, input.ApiInput.Facets, portfolio); } } if (hasGroup) { /* Groupement. */ a.Filter(GroupAggs, f => { /* Critère de post-filtrage répété sur les groupes, puisque ce sont des agrégations qui par définition ne sont pas affectées par le post-filtrage. */ if (hasPostFilter) { f.Filter(q => q.QueryString(qs => qs.Query(postFilterQuery))); } return(f.Aggregations(aa => aa /* Groupement. */ .Terms(groupFieldName, st => st .Field(groupFieldName) .Aggregations(g => g.TopHits(_topHitName, x => x.Size(input.GroupSize)))) /* Groupement pour les valeurs nulles */ .Missing(groupFieldName + MissingGroupPrefix, st => st .Field(groupFieldName) .Aggregations(g => g.TopHits(_topHitName, x => x.Size(input.GroupSize)))))); }); } return(a); }); } return(s); }); res.CheckStatus("AdvancedQuery"); /* Extraction des facettes. */ var facetListOutput = new List <FacetOutput>(); if (hasFacet) { var aggs = res.Aggs; foreach (var facetDef in facetDefList) { facetListOutput.Add(new FacetOutput { Code = facetDef.Code, Label = facetDef.Label, IsMultiSelectable = facetDef.IsMultiSelectable, Values = GetHandler(facetDef).ExtractFacetItemList(aggs, facetDef, res.Total) }); } } /* Ajout des valeurs de facettes manquantes (cas d'une valeur demandée par le client non trouvée par la recherche.) */ if (input.ApiInput.Facets != null) { foreach (var facet in input.ApiInput.Facets) { var facetItems = facetListOutput.Single(f => f.Code == facet.Key).Values; /* On ajoute un FacetItem par valeur non trouvée, avec un compte de 0. */ foreach (var value in facet.Value) { if (!facetItems.Any(f => f.Code == value)) { facetItems.Add(new FacetItem { Code = value, Label = facetDefList.FirstOrDefault(fct => fct.Code == facet.Key)?.ResolveLabel(value), Count = 0 }); } } } } /* Extraction des résultats. */ var resultList = new List <TDocument>(); var groupResultList = new List <GroupResult <TDocument> >(); if (hasGroup) { /* Groupement. */ var bucket = (BucketAggregate)res.Aggs.Filter(GroupAggs).Aggregations[groupFieldName]; foreach (KeyedBucket <object> group in bucket.Items) { var list = ((TopHitsAggregate)group.Aggregations[_topHitName]).Documents <TDocument>().ToList(); groupResultList.Add(new GroupResult <TDocument> { Code = group.Key.ToString(), Label = facetDefList.First(f => f.Code == apiInput.Group).ResolveLabel(group.Key), List = list, TotalCount = (int)group.DocCount }); } /* Groupe pour les valeurs null. */ var nullBucket = (SingleBucketAggregate)res.Aggs.Filter(GroupAggs).Aggregations[groupFieldName + MissingGroupPrefix]; var nullTopHitAgg = (TopHitsAggregate)nullBucket.Aggregations[_topHitName]; var nullDocs = nullTopHitAgg.Documents <TDocument>().ToList(); if (nullDocs.Any()) { groupResultList.Add(new GroupResult <TDocument> { Code = FacetConst.NullValue, Label = input.FacetQueryDefinition.FacetNullValueLabel ?? "focus.search.results.missing", List = nullDocs, TotalCount = (int)nullBucket.DocCount }); } resultList = null; } else { /* Liste unique. */ resultList = res.Documents.ToList(); groupResultList = null; } /* Construction de la sortie. */ var output = new QueryOutput <TDocument> { List = resultList, Facets = facetListOutput, Groups = groupResultList, Query = apiInput, TotalCount = res.Total }; return(output); }