Last updated Oct 3, 2024

How to create a new custom index and interact with it using a custom SearchIndexAccessor

AvailabilityConfluence 7.17 or later

This guide covers how you can create a custom index for your app.

In Confluence 7.17, we introduced a new interface CustomSearchIndexRegistry (located under com.atlassian.confluence.search.v2) and a Spring component with the same name, that's available to apps.

1
2
/**
 * This interface is available to plugins and allows 3rd-party vendors to add their own custom indexes
 *
 * @since 7.17
 */
public interface CustomSearchIndexRegistry {
    /**
     * This method can be called multiple times but a new {@link SearchIndexAccessor} instance will be created only once
     * for the first call. The same instance will be returned by subsequent calls to the method with the same name.
     * <p>
     * It is highly recommended that the prefix <code>name</code> and <code>relativeIndexPath</code> are prefixed with
     * the plugin key to avoid naming conflicts and/or unintentionally sharing indexes with another plugin.
     *
     * @param name               the unique name of the custom index. The name should have a plugin key as its prefix
     *                           to avoid naming conflicts. If the custom index directory is not created, it will be created under the default index directory.
     * @param relativeIndexPath  the path relative to the confluence lucene index directory expressed as a String. You must use forward slashes as seperators i.e plugin/usage. Underlying impl is filesystem independent.
     * @param scoringStrategy    the scoring strategy that will be used to scan the documents.
     * @param analyzerDescriptorProvider provider for a {@link com.atlassian.confluence.plugins.index.api.MappingAnalyzerDescriptor} representing a Lucene Analyzer, or null if {@link org.apache.lucene.analysis.core.KeywordAnalyzer} is used.
     * @return a {@link SearchIndexAccessor} that can access to this custom index.
     */
    SearchIndexAccessor add(String name, String relativeIndexPath, ScoringStrategy scoringStrategy, @Nullable AnalyzerDescriptorProvider analyzerDescriptorProvider) throws SearchIndexAccessException;

    /**
     * This method returns the {@link SearchIndexAccessor} corresponding to the index represented by its unique name.
     *
     * @param name the name of the custom index
     * @return a {@link SearchIndexAccessor} that can access to this custom index
     * @throws SearchIndexAccessException if the custom search index does not exist
     */
    SearchIndexAccessor get(String name) throws SearchIndexAccessException;

    /**
     * Remove the custom index from the registry. The internal lucene connection will be also closed.
     *
     * @param name the name of the custom index
     * @throws SearchIndexAccessException if the custom search index does not exist
     */
    void remove(String name) throws SearchIndexAccessException;
}

To make it more convenient for apps to create and interact with their own custom indexes, we also provide a new abstract class called DelegatingSearchIndexAccessor which simply encapsulates a SearchIndexAccessor instance and delegates all operations to this instance.

If you want to initialize your own SearchIndexAccesor Spring component, you can write a class that extends DelegatingSearchIndexAccessor as follows:

1
2
@Component
public class EdgeSearchIndexAccessor extends DelegatingSearchIndexAccessor {
    public static final String EDGE = "edge";

    @Autowired
    public EdgeSearchIndexAccessor(CustomSearchIndexRegistry customSearchIndexRegistry) {
        super(customSearchIndexRegistry, EDGE, ScoringStrategy.EDGE, null);
    }
}

The new custom Spring component of type SearchIndexAccessor can then be injected into any other Spring components as needed.

Apps can still inject the CustomSearchIndexRegistry Spring bean and use it directly. This is what is happening under the hood when extending the DelegatingSearchIndexAccessor. Here's an example of creating a search index with name "custom", with a relative path of "customRelativePath", default scoring strategy and a StandardAnalyzer:

1
2
@Component
public class MyService {
	private final SearchIndexAccessor searchIndexAccessor;

  	@Autowired 
	public MyService(CustomSearchIndexRegistry customSearchIndexRegistry) {
		this.searchIndexAccessor = customSearchIndexRegistry("custom", "customRelativePath", ScoringStrategy.DEFAULT, new StandardAnalyzerDescriptor());
	}
}

Rebuilding your index

Admins often need to manually rebuild their search indexes for a variety of reasons. Typically, they do so via content index administration. We recommend that your app also rebuilds its custom index when that happens. This can be done by creating an event listener for ReIndexRequestEvent.

1
2
public class ReindexListener {

    @EventListener
    public void onReindexRequested(ReIndexRequestEvent event) {
        // reindex documents onto your custom index via SearchIndexAccessor 
    }
}

Rate this page: