Developer forum

Forum » Development » (8.9) When searching index by IQueryService.Query, how to include facets?

(8.9) When searching index by IQueryService.Query, how to include facets?

Evaldas Raisutis
Evaldas Raisutis
Reply

I can do a search like so:

IQueryResult results = queryService.Query(queryService.LoadQuery(repository, query), querySettings);

But I also want to retrieve facets based on this query. I can see that QuerySettings class has a property Facets, which is an IEnumerable of IFacetGroup. But the FacetGroup implementation has a ton of properties - which ones need to be set to make this work? If I only set Name property (to match name of the facet we have) then Search just throws:

Object reference not set to an instance of an object
at Dynamicweb.Indexing.Lucene.LuceneIndexProvider.DoFacetSearch(IFacetGroup facets, FieldDefinitionBase[] fields, IndexReader reader, IQuery query, QuerySettings settings, Query originalQuery, IList`1 exceptions)
at Dynamicweb.Indexing.Lucene.LuceneIndexProvider.SearchInternal(IQuery query, QuerySettings settings)

Which properties on FacetGroup class need to be filled in?


Replies

 
Evaldas Raisutis
Evaldas Raisutis
Reply

So appearently IQueryService.LoadFacets is a thing :) 

 
Evaldas Raisutis
Evaldas Raisutis
Reply

So appearently IQueryService.LoadFacets is a thing :) 

 
Nicolai Pedersen
Reply

Hi Evaldis

I've found the 8 code that loads the facet definitions from XML files - see below. That might help you.

public static IFacetGroup ConvertToFacets(JObject obj)
        {

            IFacetGroup facets;

            string type = (string)obj["Type"];
            if (!string.IsNullOrWhiteSpace(type))
            {
                Type indexType = Type.GetType(type);
                facets = Activator.CreateInstance(indexType) as IFacetGroup;
            }
            else
            {
                facets = new FacetGroup();
            }

            if (facets != null)
            {

                // Name
                string facetsName = (obj["Name"] != null) ? (string)obj["Name"] : null;
                facets.Name = facetsName;

                // Filename
                facets.FileName = (obj["FileName"] != null) ? (string)obj["FileName"] : null; ;


                // Meta
                var meta = new Dictionary<string, string>();
                JObject jMeta = (JObject)obj["Meta"];

                if (jMeta != null)
                {
                    foreach (var prop in jMeta.Properties())
                    {
                        meta.Add(prop.Name, (string)prop.Value);
                    }
                }

                facets.Meta = meta;

                // Settings
                var settings = new Dictionary<string, string>();
                JObject jSettings = (JObject)obj["Settings"];

                if (jSettings != null)
                {
                    foreach (var prop in jSettings.Properties())
                    {
                        settings.Add(prop.Name, (string)prop.Value);
                    }
                }

                facets.Settings = settings;

                // Source
                JObject jSource = (JObject)obj["Source"];
                FacetSource facetSource = new FacetSource();
                if (jSource != null)
                {
                    facetSource.Repository = (string)jSource["Repository"];
                    facetSource.Item = (string)jSource["Item"];
                }
                facets.Source = facetSource;


                // Facets

                var items = new List<Facet>();
                JArray jItems = (JArray)obj["Items"];

                if (jItems != null)
                {

                    foreach (var jFacet in jItems)
                    {
                        string facetName = (string)jFacet["Name"];
                        string facetQueryParameter = (string)jFacet["QueryParameter"];
                        string facetTypeName = (string)jFacet["Type"];
                        string facetField = (string)jFacet["Field"];


                        Facet facet = new Facet() { Name = facetName, QueryParameter = facetQueryParameter, Type = facetTypeName, Field = facetField };

                        var facetOptions = new List<FacetOption>();
                        JArray jFacetOptions = (JArray)jFacet["Options"];

                        if (jFacetOptions != null)
                        {
                            foreach (var jFacetOption in jFacetOptions)
                            {
                                string facetOptionName = (string)jFacetOption["Name"];
                                string facetOptionTitle = (string)jFacetOption["Title"];
                                string facetOptionValue = (string)jFacetOption["Value"];

                                FacetOption facetOption = new FacetOption() { Name = facetOptionName, Value = facetOptionValue };

                                facetOptions.Add(facetOption);
                            }
                        }

                        facet.Options = facetOptions;

                        items.Add(facet);

                    }
                }

                facets.Items = items;

            }

            return facets;
        }

        public static IFacetGroup ConvertToFacets(XElement obj)
        {

            XElement root = obj;
            if (root.Name.LocalName.Equals("Facets"))
            {

                IFacetGroup facets;
                if (root.Attribute("Type") != null)
                {
                    Type indexType = Type.GetType(root.Attribute("Type").Value);
                    facets = Activator.CreateInstance(indexType) as IFacetGroup;
                }
                else
                {
                    facets = new FacetGroup();
                }

                if (facets != null)
                {

                    // Name
                    string facetsName = (root.Attribute("Name") != null) ? root.Attribute("Name").Value : null;
                    facets.Name = facetsName;

                    // Filename
                    facets.FileName = null;

                    // Meta
                    var meta = new Dictionary<string, string>();

                    var metaElements = root.Elements("Meta");
                    if (metaElements != null)
                    {
                        foreach (var el in metaElements)
                        {
                            if (el.Attribute("Name") != null && el.Attribute("Value") != null)
                            {
                                meta.Add(el.Attribute("Name").Value, el.Attribute("Value").Value);
                            }
                        }
                    }
                    facets.Meta = meta;

                    // Settings
                    var settingsElement = root.Element("Settings");
                    var settings = new Dictionary<string, string>();

                    if (settingsElement != null)
                    {
                        foreach (var el in settingsElement.Elements())
                        {
                            settings.Add(el.Name.LocalName, el.Value);
                        }
                    }

                    facets.Settings = settings;

                    // Source
                    var sourceElement = root.Element("Source");

                    FacetSource facetSource = new FacetSource();
                    if (sourceElement != null)
                    {
                        facetSource.Repository = (sourceElement.Attribute("Repository") != null) ? sourceElement.Attribute("Repository").Value : null; ;
                        facetSource.Item = (sourceElement.Attribute("Item") != null) ? sourceElement.Attribute("Item").Value : null; ;
                    }
                    facets.Source = facetSource;

                    // Facets
                    var items = new List<Facet>();
                    var facetElements = root.Elements("Facet");

                    foreach (var facetElement in facetElements)
                    {

                        string facetName = (facetElement.Attribute("Name") != null) ? facetElement.Attribute("Name").Value : null;
                        string facetQueryParameter = (facetElement.Attribute("QueryParameter") != null) ? facetElement.Attribute("QueryParameter").Value : null;
                        string facetType = (facetElement.Attribute("Type") != null) ? facetElement.Attribute("Type").Value : null;
                        string facetField = (facetElement.Attribute("Field") != null) ? facetElement.Attribute("Field").Value : null;

                        Facet facet = new Facet() { Name = facetName, QueryParameter = facetQueryParameter, Type = facetType, Field = facetField };

                        var facetOptions = new List<FacetOption>();
                        var facetOptionElements = facetElement.Elements("Option");
                        if (facetOptionElements != null)
                        {
                            foreach (var facetOptionElement in facetOptionElements)
                            {
                                string facetOptionName = (facetOptionElement.Attribute("Name") != null) ? facetOptionElement.Attribute("Name").Value : null;
                                string facetOptionTitle = (facetOptionElement.Attribute("Title") != null) ? facetOptionElement.Attribute("Title").Value : null;
                                string facetOptionValue = (facetOptionElement.Attribute("Value") != null) ? facetOptionElement.Attribute("Value").Value : null;
                                FacetOption facetOption = new FacetOption() { Name = facetOptionName, Value = facetOptionValue };
                                facetOptions.Add(facetOption);
                            }
                        }

                        facet.Options = facetOptions;
                        items.Add(facet);
                    }

                    facets.Items = items;

                    return facets;
                }
                else
                {
                    if (root.Attribute("Type") != null)
                        throw new Exception(string.Format("Cannot instantiate Facets of type  '{0}'", root.Attribute("Type").Value));
                    else
                        throw new Exception(string.Format("Cannot instantiate Facets"));
                }
            }
            else
            {
                throw new Exception(string.Format("Root is an not a 'Facets' element"));
            }


        }

 
Nicolai Pedersen
Reply

And here is some other code - custom from a Dynamicweb 9 solution - it might also give you some pointers:

 

[Subscribe(Dynamicweb.Ecommerce.Notifications.Ecommerce.Querying.BeforeQuery), Subscribe(Dynamicweb.Indexing.Lucene.Notifications.OnAfterQueryParsed)]
    public class BeforeQueryDynamicFacetNotificationSubscriber : NotificationSubscriber
    {


        internal const string RemovedFacetKey = "RemovedFacetKey";
        public override void OnNotify(string notification, NotificationArgs args)
        {
            if (notification.ToLower() == Dynamicweb.Indexing.Lucene.Notifications.OnAfterQueryParsed.ToLower())
            {
                var qargs = args as Dynamicweb.Indexing.Lucene.Notifications.QueryParsedNotification;
                return;
            }
            
            var queryArgs = args as BeforeQueryArgs;
            var map = new Dictionary<string, Dictionary<string, string>>();
            var languageId = Dynamicweb.Ecommerce.Common.Context.LanguageID;
            var productId = HttpContext.Current.Request["product"];
            var facets = queryArgs.Settings.Facets as List<IFacetGroup>;

            var searchVariants = Dynamicweb.Context.Current.Request.GetString("VariantsTextSearch");

            facets.Clear();

            var cmdBuilder = new CommandBuilder();

            cmdBuilder.Add(@"
                SELECT FieldTranslationFieldId, FieldTranslationFieldLabel, FieldTranslationLanguageId FROM
                (
                 SELECT
                  FieldValueFieldId
                 FROM
                  EcomProductCategoryFieldValue
                 WHERE
                  FieldValueProductId = {0}
                  AND FieldValueFieldCategoryId = 'LISTPROPS'
                  AND FieldValueProductLanguageId = {1}
                  AND FieldValueValue <> '' AND FieldValueValue IS NOT NULL
                 GROUP BY
                  FieldValueFieldId
                ) t LEFT JOIN EcomProductCategoryFieldTranslation ON FieldValueFieldId = FieldTranslationFieldId", productId, languageId);


            using (var reader = Database.CreateDataReader(cmdBuilder))
            {

                while (reader.Read())
                {
                    var fieldId = reader["FieldTranslationFieldId"] as string;
                    var fieldLabel = reader["FieldTranslationFieldLabel"] as string;
                    var fieldLanguageId = reader["FieldTranslationLanguageId"] as string;

                    if (!map.ContainsKey(fieldId))
                    {
                        map[fieldId] = new Dictionary<string, string>();
                    }
                    if (!map[fieldId].ContainsKey(fieldLanguageId))
                    {
                        map[fieldId][fieldLanguageId] = fieldLabel;
                    }
                }

            }

            var facetList = new List<Facet>();
            var dctRemovedFacets = new Dictionary<string, Facet>();

            GroupExpression groupExpression = queryArgs.Query.Expression as GroupExpression;
            GroupExpression orGrpExp = Expression.Group(false, OperatorType.Or, new List<Expression>()) as GroupExpression;

            

            foreach (var key in map.Keys)
            {

                var labels = map[key];
                string label = null;

                if (!string.IsNullOrEmpty(labels[languageId]))
                {
                    label = labels[languageId];
                }
                if (string.IsNullOrEmpty(label))
                {
                    foreach (var labelCandidate in labels.Values)
                    {
                        if (!string.IsNullOrEmpty(labelCandidate))
                        {
                            label = labelCandidate;
                            break;
                        }
                    }
                }
                if (string.IsNullOrEmpty(label))
                {
                    label = key;
                }

                var facet = new Facet();
                facet.Name = label;
                facet.Field = $"ProductCategory|LISTPROPS|{key}";
                facet.QueryParameter = key;
                facet.TypeName = "Field";
                facet.Options = new List<FacetOption>();
                
                if (!string.IsNullOrEmpty(searchVariants))
                {
                    var fe = FieldExpression.Field($"ProductCategory|LISTPROPS|{key}", $"ProductCategory|LISTPROPS|{key}");
                    var pe = ParameterExpression.Parameter("VariantsTextSearch");
                    var exp = Dynamicweb.Indexing.Querying.Expressions.Expression.Binary(Dynamicweb.Indexing.Querying.Expressions.OperatorType.Equal, fe, pe);
                    orGrpExp.Expressions.Add(exp);
                    
                }
                var p = new Dynamicweb.Indexing.Lucene.LuceneIndexProvider();
                
                Dynamicweb.Diagnostics.ExecutionTable.Current.Add($"Index query: " + queryArgs.Query.ToString());

                //Create website setting for large facets - use website setting here:
                if (key == "LFLD553")
                {
                    dctRemovedFacets.Add(key, facet);
                    continue;

                }
                facetList.Add(facet);

            }

            //Used for facet fields containing data worth analyzing
            if (!string.IsNullOrEmpty(searchVariants))
            {
                var fe = FieldExpression.Field("AnalyzedFacets", "AnalyzedFacets");
                var pe = ParameterExpression.Parameter("VariantsTextSearch");
                var exp = Dynamicweb.Indexing.Querying.Expressions.Expression.Binary(Dynamicweb.Indexing.Querying.Expressions.OperatorType.Contains, fe, pe);
                orGrpExp.Expressions.Add(exp);
            }

            groupExpression.Expressions.Add(orGrpExp);

            System.Web.HttpContext.Current.Items[RemovedFacetKey] = dctRemovedFacets;

            var facetGroup = new FacetGroup();
            facetGroup.Name = "temporary";
            facetGroup.Items = facetList;

            facets.Add(facetGroup);


        }
    }

 
Nicolai Pedersen
Reply

And this is what LoadFacets do in 8 - it calls the FacetGroupHelper.ConvertToFacets posted above.

public IFacetGroup LoadFacets(string repository, string item)
        {
            return LoadFacets(Path.Combine(Dynamicweb.Repositories.RepositoryService.BaseFolder, repository, item));
        }

        public IFacetGroup LoadFacets(string filename)
        {


            FileInfo fi = new FileInfo(filename);
            XDocument xmldoc = XDocument.Load(filename);

            IFacetGroup facets = FacetGroupHelper.ConvertToFacets(xmldoc.Root);

            // Name
            string facetsName = (xmldoc.Root.Attribute("Name") != null) ? xmldoc.Root.Attribute("Name").Value : fi.Name;
            facets.Name = facetsName;

            // Filename
            facets.FileName = filename;

            return facets;

        }

 
Evaldas Raisutis
Evaldas Raisutis
Reply

Thanks Nicolai :) 

 
Nicolai Pedersen
Reply
This post has been marked as an answer

Grab a beer, and make it work :-).

Votes for this answer: 1

 

You must be logged in to post in the forum