Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Drew Garratt 44 posts 192 karma points
    Feb 26, 2013 @ 15:27
    Drew Garratt
    0

    Indexing Relationships with a Examine Extension

    Hi everyone,

    Following some advice from Hendy Racher I found that the only way to get Umbraco index the node to node relationships in my solution woul be to add a Examine Extension.

    Lots of reading later and with lots of examples from Ismail Mayat I've finally built what I think should be the answer to my problem. The problem is it dosen't seem to be working as I expected. So far I haven't managed to get the extension adding anything to my index, could be I've missed the obvious but any advice would be a appreciated.

    using System;
    using System.Collections.Generic;
    using umbraco.BusinessLogic;
    using Examine;
    using UmbracoExamine;
    using umbraco.presentation.nodeFactory;
    using System.Text;
    using umbraco;
    using umbraco.cms.businesslogic.relation;
    
    namespace Client.classes
    {
        public class ExamineEvents : ApplicationBase
        {
            // Configuration variables
            // Target Indexer - Target Document Alias to be index - Target relationship aliases (to be looped though and added)
            private const string Indexer = "BootstrapENIndexer";
            private const string TargetDocumentAlias = "Textpage";
            private readonly List _relationAliases = new List { "TestRelation" };
            public ExamineEvents()
            {
                //Add event handler for 'GatheringNodeData' on our 'Indexer'
                ExamineManager.Instance.IndexProviderCollection[Indexer].GatheringNodeData += new EventHandler(ExamineEvents_GatheringNodeData);
            }
            // Event handler for GatheringNodeIndex.
            //This will fire everytime Examine is creating/updating an index for an item
            void ExamineEvents_GatheringNodeData(object sender, IndexingNodeDataEventArgs e)
            {
                //Build Index Node
                umbraco.NodeFactory.Node theNode = new umbraco.NodeFactory.Node(e.NodeId);
                //check if this is 'Content' (as opposed to media, etc...)
                if (e.IndexType == IndexTypes.Content)
                {
                    //If the current node matches our targe alias
                    if (theNode.NodeTypeAlias == TargetDocumentAlias)
                    {
                        //For each relationship alias
                        foreach (var relationAlias in _relationAliases)
                        {
                            // Get relations by relation alias
                            RelationType relationType = RelationType.GetByAlias(relationAlias);
                            Relation[] relations = Relation.GetRelations(e.NodeId, relationType);
                            // For each realationship in our matched node
                            foreach (Relation relation in relations)
                            {
                                // Get the nodename of the related node
                                var relatedNode = uQuery.GetNode(relation.Id).Name;
                                if (relatedNode != string.Empty)
                                {
                                    //Add related node name to index list
                                    e.Fields.Add("__" + TargetDocumentAlias, relatedNode);
                                }
                            }
                        }
                    }
                    //Add all additional relations to index
                    AddToContentsField(e);
                }
            }
            private void AddToContentsField(IndexingNodeDataEventArgs e)
            {
                Dictionary fields = e.Fields;
                var combinedFields = new StringBuilder();
                foreach (KeyValuePair keyValuePair in fields)
                {
                    combinedFields.AppendLine(keyValuePair.Value);
                }
                e.Fields.Add("contents", combinedFields.ToString());
            }
        }
    }
    
  • Drew Garratt 44 posts 192 karma points
    Feb 27, 2013 @ 15:41
    Drew Garratt
    0

    Hi everyone,

    Really should have mentioned I'm trying this all out in V6 >.<;

    Still scratching my chin over this one. I found a suggestion to use log statements as a means of debuging whether the event was firing correctly

    Log.Add(LogTypes.Notify, -1, "We are watching yooou from examine event"); 

    Adding something like that to my extension netted me

    using System;
    using System.Collections.Generic;
    using umbraco.BusinessLogic;
    using Examine;
    using UmbracoExamine;
    using umbraco.presentation.nodeFactory;
    using System.Text;
    using umbraco;
    using umbraco.cms.businesslogic.relation;
    
    namespace Client.classes
    {
        public class ExamineEvents : ApplicationBase
        {
            // Configuration variables
            // Target Indexer - Target Document Alias to be index - Target relationship aliases (to be looped though and added)
            private const string Indexer = "BootstrapENIndexer";
            private const string TargetDocumentAlias = "Textpage";
            private readonly List _relationAliases = new List { "TestRelation" };
            public ExamineEvents()
            {
                //Add event handler for 'GatheringNodeData' on our 'Indexer'
                ExamineManager.Instance.IndexProviderCollection[Indexer].GatheringNodeData += new EventHandler(ExamineEvents_GatheringNodeData);
            }
            // Event handler for GatheringNodeIndex.
            //This will fire everytime Examine is creating/updating an index for an item
            void ExamineEvents_GatheringNodeData(object sender, IndexingNodeDataEventArgs e)
            {
                //Build Index Node
                umbraco.NodeFactory.Node theNode = new umbraco.NodeFactory.Node(e.NodeId);
                //check if this is 'Content' (as opposed to media, etc...)
                if (e.IndexType == IndexTypes.Content)
                {
                    //If the current node matches our targe alias
                    if (theNode.NodeTypeAlias == TargetDocumentAlias)
                    {
                        //For each relationship alias
                        foreach (var relationAlias in _relationAliases)
                        {
                            // Get relations by relation alias
                            RelationType relationType = RelationType.GetByAlias(relationAlias);
                            Relation[] relations = Relation.GetRelations(e.NodeId, relationType);
                            // For each realationship in our matched node
                            foreach (Relation relation in relations)
                            {
                                // Get the nodename of the related node
                                var relatedNode = uQuery.GetNode(relation.Child.Id).Name;
                                if (relatedNode != string.Empty)
                                {
                                    //Add related node name to index list
                                    e.Fields.Add("__" + TargetDocumentAlias, relatedNode);
                                    Log.Add(LogTypes.Notify, -1, "Event has added a relation to the index");
                                }
                            }
                        }
                    }
                    //Add all additional relations to index
                    AddToContentsField(e);
                }
            }
            private void AddToContentsField(IndexingNodeDataEventArgs e)
            {
                Dictionary fields = e.Fields;
                var combinedFields = new StringBuilder();
                foreach (KeyValuePair keyValuePair in fields)
                {
                    combinedFields.AppendLine(keyValuePair.Value);
                }
                e.Fields.Add("contents", combinedFields.ToString());
            }
        }
    }
    

    Unfortunately this dosen't seem to have added anything meaninful to UmbracoTraceLog

    Also a examniation of the Lucene index using LUKE shows no new "Availble Fields" as I would expect to see

    Anyone out there have any ideas as to what I may have missed?

  • Drew Garratt 44 posts 192 karma points
    Mar 07, 2013 @ 12:12
    Drew Garratt
    100

    Well it's been a week but despite the rather lengthy setback I've fixed it ^-^

    There where a couple of things that I was doing wrong based on following exaples of this class but in case anyone ever needs can be found bellow.

    Using Umbraco 6.0.2

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Linq;
    using umbraco;
    using Umbraco.Core;
    using umbraco.BusinessLogic;
    using umbraco.cms.businesslogic;
    using umbraco.cms.businesslogic.web;
    using umbraco.cms.businesslogic.relation;
    using umbraco.NodeFactory;
    using Examine;
    using UmbracoExamine;
    
    namespace Umbraco.Extensions
    {
        public class ExamineEvents : ApplicationBase
        {
            // Configuration variables
            // Target Indexer - Target Parent (the partent of all the relationships we are indexing - Target Documents (all documents types that are related) - Target relationship aliases (to be looped though and added)
            private const string Indexer = "BootstrapENIndexer";
            private const string TargetParentDocument = "Job";
            private readonly List _TargetDocumentAliases = new List { "Job", "Company", "SpecialistArea", "Contract", "Hours", "Salary", "CareerLevel", "EducationLevel" };
            private readonly List _relationAliases = new List { "company", "SpecialistAreas", "contractType", "Hours", "salaryRange", "careerLevels", "educationLevels" };
    
            public ExamineEvents()
            {
                //Add event handler for 'GatheringNodeData' 
                ExamineManager.Instance.IndexProviderCollection[Indexer].GatheringNodeData += new EventHandler(ExamineEvents_GatheringNodeData);
            }
    
    
            // Event handler for GatheringNodeIndex.
            // This will fire everytime Examine is creating/updating an index for an item
    
            void ExamineEvents_GatheringNodeData(object sender, IndexingNodeDataEventArgs e)
            {
                //Build Index Node
                umbraco.NodeFactory.Node theNode = new umbraco.NodeFactory.Node(e.NodeId);
                //check if this is 'Content' (as opposed to media, etc...)
                if (e.IndexType == IndexTypes.Content)
                {
                    //For Each Document Type in target list
                    foreach (var TargetDocumentAlias in _TargetDocumentAliases)
                    {
                        // If current node matches our current Document Type
                        if (theNode.NodeTypeAlias == TargetDocumentAlias)
                        {
                            // Create string builder to add our relationships to as they are found
                            var comibineRelations = new StringBuilder();
    
                            // For each relationship alias in our target list
                            foreach (var relationAlias in _relationAliases)
                            {
                                // Get relations by relation alias
                                RelationType relationType = RelationType.GetByAlias(relationAlias);
                                Relation[] relations = Relation.GetRelations(e.NodeId, relationType);
    
                                // For each realationship in our matched node
                                foreach (Relation relation in relations)
                                {
                                    // Create a empty string varible to hold our related node id
                                    var relatedNode = string.Empty;
    
                                    // If the current node is the parent...
                                    if (theNode.NodeTypeAlias == TargetParentDocument)
                                    {
                                        //Store relations child ID in string
                                        relatedNode = relation.Child.Id.ToString();
                                    }
                                    else
                                    {
                                        //Store relations parent ID in string
                                        relatedNode = relation.Parent.Id.ToString();
                                    }
                                    if (relatedNode != string.Empty)
                                    {
                                        //Add each relation ID to string making sure to pad the values with space for Lucene
                                        comibineRelations.Append(relatedNode + " ");
                                    }
                                }
                            }
                            // Send our related string to be written out to the index
                            e.Fields.Add("relations", comibineRelations.ToString());
                        }
                    }
                    AddToContentsField(e);
                }
            }
    
            private void AddToContentsField(IndexingNodeDataEventArgs e)
            {
                Dictionary fields = e.Fields;
                var combinedFields = new StringBuilder();
                foreach (KeyValuePair keyValuePair in fields)
                {
                    combinedFields.AppendLine(keyValuePair.Value);
                }
                e.Fields.Add("contents", combinedFields.ToString());
            }
    
        }
    }
    

    I've tried to keep my code commented to make this as easy to follow as I can. I got quite lost following some of the lengthier examples from the forum.

    What this class actually gives you is rather useful. You end up with a space delimited list of related ID's for each node added to your examine index under the field "relations".

    The great thing about this is that you can then use raw Lucene queries to get at all related nodes with simple queries.

    For example, in the jobs site I'm working on, say you'd like to find all the jobs that have "engineer" in the title are "part time" and are for "mechanical engineering" specialist. Because each piece of related information is created using relationships, the query is as simple as looking up engineer by keyword and the two 'attributes' by ID. In this case [ +nodeName:engineer +relations:(+1331 +1338) ].

    Because we are looking for these attributes by ID rather than by nodeName and because we've added these into a single field within the index we can search for any number of attributes in any order and allways return the same results.

    Hope that helps anyone else stuck in the same boat.

    Drew

  • Jeremy Loeckler 10 posts 52 karma points
    Apr 26, 2013 @ 12:58
    Jeremy Loeckler
    0

    Thanks for posting the complete solution! This is highly relevant for a similar challenge I'm facing.

  • Drew Garratt 44 posts 192 karma points
    Apr 27, 2013 @ 22:25
    Drew Garratt
    0

    Glad I could help Jeremy ^-^

Please Sign in or register to post replies

Write your reply to:

Draft