Adding content to search

Telligent Evolution provides search functionality for users to find exactly what they are looking for. Most content in the platform can be found using search. This includes groups, applications, posts, comments, users, etc. Developers adding new content types will want to include their content in the search results to give it maximum visibility and accessibility. This document describes the how to include custom content in search results.

First, the content must be added to the search index - and to do that it must be searchable. To make an IContent type searchable, it needs to implements the Telligent.Evolution.Extensibility.Content.Version1.ISearchableContentType interface. If you’re unfamiliar with IContent and how it’s used in Telligent Evolution, see this documentation. The ISearchableContentType is defined as followed.

namespace Telligent.Evolution.Extensibility.Content.Version1
{
	public interface ISearchableContentType : IContentType
	{
		void SetIndexStatus(Guid[] contentIds, bool isIndexed);
		IList<SearchIndexDocument> GetContentToIndex();
		int[] GetViewSecurityRoles(Guid contentId);

		string GetViewHtml(IContent content, Target target); 
		bool IsCacheable { get; }
		bool VaryCacheByUser { get; }
	}
}

The table below explains the use of each method and parameter.

Method Parameters Description
void SetIndexStatus()   Called when the indexed status of content has changed. This can be because it was indexed or the content was updated and needs to be reindexed. Developers will need to create their own way of tracking the indexed state of their content.
  Guid[] contentIds The ContentIds of the content to update; all of these will match the ContentTypeId of the ISearchableContentType.
  bool isIndexed True if the content has been indexed, false if it has not or needs to be.
IList<SearchIndexDocument> GetContentToIndex()   Returns a list of the SearchIndexDocuments representing the content that should be indexed but isn't yet. For performance reasons, this should return a finite number of results and not every piece of content yet to be indexed. Most ContentTypes return up to 1000 results per method call. Use PublicApi.SearchIndexing.NewDocument() to create the SearchIndexDocument for each piece of content to index, then add fields to the document using document.AddField(
PublicApi.SearchIndexing.Contstants.[Property], value).
int[] GetViewSecurityRoles()   Search uses site roles to control what results are returned to each user. This method should return the role Ids that can view this content. This method is automatically called when creating the SearchIndexDocument.
  Guid contentId ContentId of content to check view permissions for.
string GetViewHtml()   Called when rendering search results. The IContent type will match the type in the plugin. This method returns the HTML for the content to be displayed in the search results widget.
  IContent content Content returned by a search query.
  Target target The target being rendered to, most commonly Web or Email.
bool IsCacheable   If true, the rendered html for a piece of content is cached.
bool VaryCacheByUser   If true, the rendered html for a piece of content will be cached on a per user basis.

Indexing the content uses the SetIndexStatus(), GetContentToIndex(), and GetViewSecurityRoles() methods while displaying the content as a search result uses the GetViewHtml() method and the IsCacheable and VaryCacheByUser properties.

Indexing content

Any ISearchableContentType plugins enabled on the site are automatically identified and called; there is no need to register the content type as there was in previous versions.


Flow chart of search indexing

GetContentToIndex() is where the majority of the indexing work is done. This method is responsible for figuring out what content isn’t indexed yet but should be, and creating a SearchIndexDocument that represents the content.

The search indexer will only process a set number of documents from any one content type at a time. This is done so that all content is indexed equally and so no one content type can hold up indexing the rest of the content on the site. This value is set in the tasks.config file and defaults to 5000. For this and performance reasons, the GetContentToIndex() should not create a SearchIndexDocument for every piece of content at once. Instead it should return a finite amount each time it’s called, most content types return 1000 at a time.

Remove Content from the Search Index when Uninstalled

It is up to the content type to remove itself from the search index when it's disabled or uninstalled.  To do this, the plugin should also implement IInstallablePlugin and in the Uninstall() method it should remove all its search content.  If this is not done, that content will continue to be returned by search but be unable to be used.

Creating the SearchIndexDocument

The SearchIndexDocument should not be created by newing up an instance of it. Instead, use the PublicApi.SearchIndexing.NewDocument() method. The method signature is
SearchIndexDocument NewDocument(Guid contentId, Guid contentTypeId, string typeName, string url, string title, string content).

contentId – Guid Id of the content.
contentTypeId – ContentTypeId of the content, this will match the value from the IContentType plugin property.
typeName – A human-readable string used to differentiate this type of content from other types. For example, a blog post has a type “blog”; this can be used when filtering search results to only blog posts by including “type:blog” in the search query.
url – The url of the content.
title – The title or subject of the content, used when finding results from a search query.
content – The body of the content, used when finding results from a search query.

The NewDocument method will automatically call the GetViewSecurityRoles() method from your plugin. This method should return the Ids of all roles that have permission to view the content. Search uses this to only return content that a user has permission to view. For example, if a blog post is in a private group that the searching user can’t access, that blog post will not show up in search results for that user.

Once the SearchIndexDocument has been created, additional fields can be added. These can include anything from PublicApi.SearchIndexing.Constants. Some fields will have already been set by NewDocument() when the SearchIndexDocument was created.

One field to take particular note of is RelatedId. This is especially useful when deleting content. The field can be added multiple times with different values. It’s a good idea to include any of the following values that apply for any particular content: the content’s group ContainerId, the ApplicationId, and if the content is the child of some content (for example, a reply to a forum thread or a comment on some content), the parent’s ContentId. Adding these values will cause the search document for this content to be automatically removed from search when its group, application, or parent content is removed, if any of them are deleted from the site for example.

Displaying content in the search results

Once the content has been indexed it can be found by search. Each content type defines how its content is rendered on the search results page. The GetViewHtml() method should return the Html to render for the specified content.

Removing content from search

When content is deleted or unapproved, it should be removed from the search index.  This is done using the PublicApi.Search.Delete(string id) method.  The id should be the ContentId, ApplicationId, or ContainerId of the object to delete.

Indexing events

Events are exposed around search indexing and rendering as well. They are accessible via PublicApi.SearchIndexing.Events. Before and after events for indexing content are exposed. If you need to add fields to a content type outside of a plugin, the before event is the place to do it. A rendering event is also exposed, allowing for plugins to modify the rendered html of content.

Search events

At times it may be useful to modify searches or the results of a search, possibly to add a filter or to modify the results. The events exposed in PublicApi.Search.SearchEvents offer plugins the opportunity to make modifications to the SearchResultsListOptions before the search query is made and to the results after a search query.

Telligent Evolution uses Solr as its default search provider. Before and after events for the Solr search are exposed via PublicApi.Search.SolrEvents. These give access to the url sent to Solr to perform the search. These events should only be used if Solr=specific modifications must be made to the url. While Solr is the default search provider, some sites may have a customized search provider other than Solr that will not execute these events so it is best to limit their use to cases where the functionality can only be achieved by using the Solr events.