I believe you need to create an IndexPopulator for your index. Make sure to implement the PopulateIndexes method. I'm pulling this pretty much directly from the v8 bridging course for searching and indexing, but I haven't put it into practice outside of that training yet. Let me know if this does the trick:
The IndexPopulator
public class TodoIndexPopulator : IndexPopulator
{
private readonly TodoValueSetBuilder _todoValueSetBuilder;
public TodoIndexPopulator(TodoValueSetBuilder productValueSetBuilder)
{
_todoValueSetBuilder = productValueSetBuilder;
RegisterIndex("TodoIndex");
}
protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
{
using (var httpClient = new WebClient())
{
var jsonData = httpClient.DownloadString("https://jsonplaceholder.typicode.com/todos/");
var data = JsonConvert.DeserializeObject<IEnumerable<ToDoModel>>(jsonData);
if (data != null)
{
foreach(var item in indexes)
{
item.IndexItems(_todoValueSetBuilder.GetValueSets(data.ToArray()));
}
}
}
}
}
This IValueSetBuilder
public class TodoValueSetBuilder : IValueSetBuilder<ToDoModel>
{
public IEnumerable<ValueSet> GetValueSets(params ToDoModel[] data)
{
foreach (var todo in data)
{
var indexValues = new Dictionary<string, object>
{
["userId"] = todo.UserId,
["id"] = todo.Id,
["title"] = todo.Title,
["completed"] = todo.Completed
};
var valueSet = new ValueSet(todo.Id.ToString(), "todo", indexValues);
yield return valueSet;
}
}
}
Composer
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class ExamineComposerPublic : IUserComposer
{
public void Compose(Composition composition)
{
//Add our component
composition.Components().Append<ExamineComponents>();
composition.RegisterUnique<TodoValueSetBuilder>();
composition.Register<TodoIndexPopulator>(Lifetime.Singleton);
composition.RegisterUnique<TodoIndexCreator>();
}
}
Take the rest of this as a starting point. It is also basically copy pasted from the v8 bridging course, but I think started messing with it and don't know what state I left it in.
IndexCreator
The IndexCreator is a LuceneIndexCreator. It returns an IEnumerable
public class TodoIndexCreator : LuceneIndexCreator
{
private ILogger ProfilingLogger { get; }
public TodoIndexCreator(ILogger profilingLogger)
{
ProfilingLogger = profilingLogger;
}
public override IEnumerable<IIndex> Create()
{
var index = new TodoExamineIndex("TodoIndex",
CreateFileSystemLuceneDirectory("TodoIndex"),
new FieldDefinitionCollection(
new FieldDefinition("userId", FieldDefinitionTypes.Integer),
new FieldDefinition("id", FieldDefinitionTypes.Integer),
new FieldDefinition("title", FieldDefinitionTypes.FullTextSortable),
new FieldDefinition("completed", FieldDefinitionTypes.FullTextSortable)),
new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30),
null,
null,
ProfilingLogger);
return new[] { index };
}
}
IndexComponent
The IndexComponent in the example I posted is where all the custom indexing logic happens. In the bridging course, it adds the todo index to the ExamineManager's list of indexes, and combines all of the fields into one aggregated field that users can search on. I won't post the whole thing, but I'll add some snippets here:
Add index to Examine Manager
foreach (var data in _todoIndexCreator.Create())
{
_examineManager.AddIndex(data);
}
Attach to IndexProviderTransformingIndexValues to make aggregate field
//we need to cast because BaseIndexProvider contains the TransformingIndexValues event
if (!(index is BaseIndexProvider indexProvider))
{
throw new InvalidOperationException("Could not cast");
}
indexProvider.TransformingIndexValues += IndexProviderTransformingIndexValues;
}
/// <summary>
/// Combine all fields into single aggregate field
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void IndexProviderTransformingIndexValues(object sender, IndexingItemEventArgs e)
{
//this is the replacement for the GatheringNodeData
if (e.ValueSet.Category == IndexTypes.Content)
{
try
{
var combinedFields = new StringBuilder();
foreach (var fieldValues in e.ValueSet.Values)
{
foreach (var value in fieldValues.Value)
{
if (value != null)
{
combinedFields.AppendLine(value.ToString());
}
}
}
e.ValueSet.Add("contents", combinedFields.ToString());
}
catch (Exception ex)
{
_logger.Error<ExamineComponents>(ex, "Error combining fields for {ValueSetId}", e.ValueSet.Id);
}
}
}
Attach to DocumentWriting to do some boosting
if (!(index is LuceneIndex luceneIndex))
{
throw new InvalidOperationException("Could not cast");
}
luceneIndex.DocumentWriting += LuceneIndex_DocumentWriting;
}
private void LuceneIndex_DocumentWriting(object sender, global::Examine.LuceneEngine.DocumentWritingEventArgs e)
{
//if its blog item and the blog tag is set to cheese boost it else set it to 1
var nodeTypeAlias = e.ValueSet.ItemType;
if (nodeTypeAlias?.ToString() == "blogpost")
{
var newsTag = e.ValueSet.GetValue("categories");
if (newsTag != null && newsTag.ToString().InvariantContains("cheese"))
{
e.Document.Boost = 1000;
}
else
{
e.Document.Boost = 1; //may have been set to cheese before and now been changed
}
}
}
How to create custom index in v8
In v7 to create custom index you had to implement ISimpleDataService interface and over ride getdata. In 8 looking at https://our.umbraco.com/Documentation/Reference/Searching/Examine/indexing/ this seems to be for Umbraco content index.
Looking at examine source with webdemo for custom non umbraco content seems like in startup you create index. Then create controller to rebuild the index with your data source see https://github.com/Shazwazza/Examine/blob/master/src/Examine.Web.Demo/Global.asax.cs
Or am i reading this wrong? Has anyone already done this?
Regards
Ismial
I believe you need to create an
IndexPopulator
for your index. Make sure to implement thePopulateIndexes
method. I'm pulling this pretty much directly from the v8 bridging course for searching and indexing, but I haven't put it into practice outside of that training yet. Let me know if this does the trick:The IndexPopulator
This IValueSetBuilder
Composer
Cool, many thanks for this. I did ask the other day on umbraco slack if bridging course had been done by anyone lol.
Im hoping to get on it soon.
Regards
Ismail
Whats in ExamineComponents and TodoIndexCreator ?
ok just found this https://gist.github.com/hartviglarsen/44743b32d4eea8eda3fb6d49b60dd547 nearly there.
Take the rest of this as a starting point. It is also basically copy pasted from the v8 bridging course, but I think started messing with it and don't know what state I left it in.
IndexCreator
The IndexCreator is a LuceneIndexCreator. It returns an IEnumerable
IndexComponent
The IndexComponent in the example I posted is where all the custom indexing logic happens. In the bridging course, it adds the todo index to the ExamineManager's list of indexes, and combines all of the fields into one aggregated field that users can search on. I won't post the whole thing, but I'll add some snippets here:
Add index to Examine Manager
Attach to IndexProviderTransformingIndexValues to make aggregate field
Attach to DocumentWriting to do some boosting
is working on a reply...