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());
}
}
}
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?
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.
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.
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
Adding something like that to my extension netted me
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?
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
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
Thanks for posting the complete solution! This is highly relevant for a similar challenge I'm facing.
Glad I could help Jeremy ^-^
is working on a reply...