I'm currently working on a Job Board site for a client on Umbraco 4.10.1 and I'm using the relationships API to manage the attributes for each job. I'm in the early phases of laying out the site when I think I've spotted a shortfall in what I wanted to achive using Examine
Using the uComponents MultiPickerRelations each job is related with bi-directional node to node relationships to each of it's key attributes.
For Example "Engineering Manager" would be related to - Contract Type: "Permanent" - Hours: "Full Time"
These relatonships should allow me to retrieve listings by there attributes such as well as keyword. Trouble is as far as I can see Examine dosen't by default index Relationships. Any ideas on the simplest way to implement indexing for this? I'd like to avoid looping though each individual search reasult for it's relations on each search as I have a feeling it's really going to slow things down.
How about an event handler that fires when Exmaine is indexing a job node to query it's relations data and add the associated attribute names space delimited into a new field ? (I'm guessing that you want to be able to search on an attribute name string like "Full Time", and return all matching jobs ?)
Hopefully the following example may be of use (not tested this at all ! you'll need to update the values for your indexer name, job docType alias and the relationType alias, this also assumes that the child in the relationship is the attribute node).
using System;
using System.Linq;
using Examine;
using umbraco;
using umbraco.businesslogic;
using umbraco.cms.businesslogic.relation;
public class IndexJobAttributes : ApplicationStartupHandler
{
public IndexJobAttributes()
{
ExamineManager.Instance.IndexProviderCollection["myIndexer"].GatheringNodeData += new EventHandler(IndexJobAttributes_GatheringNodeData);
}
private void IndexJobAttributes_GatheringNodeData(object sender, IndexingNodeDataEventArgs e)
{
if (e.IndexType == "content")
{
Node node = uQuery.GetNode(e.NodeId);
if (node != null && node.NodeTypeAlias == "Job")
{
e.Fields["jobAttributes"] = String.Join(
" ",
RelationType.GetByAlias("relateJobToAttribute")
.GetRelations(node.Id)
.Select(x => uQuery.GetNode(x.Child.Id).Name));
}
}
}
}
Thanks for this looks like the kind of thing I'm trying to do. With this kind of method I might even be able to break down diffrent relationships into diffrent collections.
Still getting to grips with the C# end of Umbraco after spending years head down in XSLT without pause for breath. Will be sure to share my progress if I get a working solution in place.
After doing some work to bring my V6 solution up to speed I've gotten started with this exetension in ernest. Trouble is so far it dosen't seem to be pushing any values into my index, sad time.
Any obvious reason anyone can spot why this might be not be returning anything?
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
+= 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());
}
}
}
Just in case it come up, tottally got it working... eventually
Umbraco version 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());
}
}
}
Adding Relationships to Examine Index Sets
Hi all,
I'm currently working on a Job Board site for a client on Umbraco 4.10.1 and I'm using the relationships API to manage the attributes for each job. I'm in the early phases of laying out the site when I think I've spotted a shortfall in what I wanted to achive using Examine
Using the uComponents MultiPickerRelations each job is related with bi-directional node to node relationships to each of it's key attributes.
For Example "Engineering Manager" would be related to
- Contract Type: "Permanent"
- Hours: "Full Time"
These relatonships should allow me to retrieve listings by there attributes such as well as keyword. Trouble is as far as I can see Examine dosen't by default index Relationships. Any ideas on the simplest way to implement indexing for this? I'd like to avoid looping though each individual search reasult for it's relations on each search as I have a feeling it's really going to slow things down.
Thanks for any help anyone can give ^-^
Hi Drew,
How about an event handler that fires when Exmaine is indexing a job node to query it's relations data and add the associated attribute names space delimited into a new field ? (I'm guessing that you want to be able to search on an attribute name string like "Full Time", and return all matching jobs ?)
Hopefully the following example may be of use (not tested this at all ! you'll need to update the values for your indexer name, job docType alias and the relationType alias, this also assumes that the child in the relationship is the attribute node).
HTH,
Hendy
Hi Hendy,
Thanks for this looks like the kind of thing I'm trying to do. With this kind of method I might even be able to break down diffrent relationships into diffrent collections.
Still getting to grips with the C# end of Umbraco after spending years head down in XSLT without pause for breath. Will be sure to share my progress if I get a working solution in place.
Thanks again,
Drew
Hi again,
After doing some work to bring my V6 solution up to speed I've gotten started with this exetension in ernest.
Trouble is so far it dosen't seem to be pushing any values into my index, sad time.
Any obvious reason anyone can spot why this might be not be returning anything?
Just in case it come up, tottally got it working... eventually
Umbraco version 6.0.2
is working on a reply...