I've created a custom search index by implementing ICustomSearchIndex
in a custom class. I want this index to be updated whenever the underlying data that it relies on is updated, but I can't figure out any way to do that (that seems correct, at least).
For example, let's say I've created a custom module, my.custommodule
, which has a custom class called my.customclass
(represented in code by CustomClassInfo
). Let's also say I've create a custom search index (because I want to be able to search on some sort of derived or calculated value that isn't directly stored in my class):
public class MyCustomSearchIndex: ICustomSearchIndex
{
public void Rebuild(SearchIndexInfo srchInfo)
{
// Some code here to create search documents and add them to the index.
}
}
Now I need to update this index whenever one of my CustomClassInfo
objects is updated. How exactly do I do this? I've tried something like this:
public class MyCustomModule: Module
{
protected override void OnInit()
{
base.OnInit();
CustomClassInfo.TYPEINFO.Events.Update.After += OnObjectChange;
CustomClassInfo.TYPEINFO.Events.Insert.After += OnObjectChange;
CustomClassInfo.TYPEINFO.Events.Delete.After += OnObjectChange;
}
void Update_After(object sender, ObjectEventArgs e)
{
CustomClassInfo ccInfo = e.Object as CustomClassInfo;
if (ccInfo != null)
{
SearchTaskInfoProvider.CreateTask(SearchTaskTypeEnum.Rebuild, "my.customclass", "CustomClassID", ccInfo.CustomClassID.ToString(), ccInfo.CustomClassID, new bool?());
}
}
}
The tasks are indeed created and run, but they don't actually rebuild any of my indexes or even update them. Which really makes total sense, because how would the system even know that MyCustomSearchIndex
indexes my.customclass
objects?
As an alternative, I tried creating my own SearchIndexer
class, which I registered in my module's OnInit
:
SearchIndexers.RegisterIndexer<MyCustomSearchIndexer>("my.customclass");
But after a rebuild that doesn't show up as an available "Index type" when creating a new index. (And, indeed, it wouldn't, because after looking into the IndexTypeSelector
control, all those values are pretty much hard coded!). What's going on here? Shouldn't I be able to register an indexer and have it show up here? I mean, sure, I can add it myself manually to the IndexTypeSelector control, but shouldn't that be populated automatically based on the registered indexers? And even if I did change it manually, what happens when an update or hotfix reverts my changes?
Another option is to find all indexes that use my custom class by using a LIKE query, then updating those:
protected override void OnInit()
{
base.OnInit();
CustomClassInfo.TYPEINFO.Events.Delete.After += OnCustomClassInfoChanged;
CustomClassInfo.TYPEINFO.Events.Update.After += OnCustomClassInfoChanged;
CustomClassInfo.TYPEINFO.Events.Insert.After += OnCustomClassInfoChanged;
}
void CustomClassInfo(object sender, ObjectEventArgs e)
{
CustomClassInfo ccInfo = e.Object as CustomClassInfo;
if (ccInfo != null)
{
var indexes = SearchIndexInfoProvider.GetSearchIndexes("IndexSettings LIKE '%ClassName=\"My.Assembly.MyCustomSearchIndexer\"%'", null);
foreach (var index in indexes)
{
SearchTaskInfoProvider.CreateTask(SearchTaskTypeEnum.Rebuild, index.IndexType, null, index.IndexName, 0, true);
}
}
}
This actually works, but it seems like a very roundabout way of having to do this. Not only that, it requires a complete rebuild of the index every single time an object is updated (which, I guess, is an inherent limitation of the fact that ICustomSearchIndex
only exposes a RebuildIndex method).
Is this the correct way of handling it? Am I missing something here? Is there a better way to do this that's just completely gone over my head? I'd rather not have to rebuild the index each time. Is there a different way to implement a custom SearchIndex
-derived class such that it can be selected from the UI?