Last updatedSep 10, 2019

Rate this page:

Using the v2 Search API

Applicable:This tutorial applies to Confluence 7.0 or higher.
Level of experience:Advanced. You should complete at least one intermediate tutorial before working through this tutorial.

Overview

The v2 search API is a low level search API that is available to third-party app developers. Because it's low level, we only recommended you use it when you can't implement your use case using CQL, which uses Confluence's high level search API.

The API is search engine agnostic, so your app is not likely to be affected if Confluence's search engine changes in the future. This tutorial will show you how to create a reusable custom query, sort it, and use it to implement a REST resource. By defining a custom query we can make the business logic reusable, easy to use, and robust to changes in the physical structure of the document in the search index.

In this tutorial we will create a plugin that defines a v2 custom query and use it to implement a REST service. The tutorial consists of 3 main elements:

  1. A custom v2 query that searches title of content objects (for example a page or attachment) in a non-standard way.
  2. A custom v2 sort that orders the search results.
  3. A REST service that returns a list of content objects satisfying the custom query ordered by the custom sort.

After completion you should be able to use the v2 search API to query data by title via REST.

Before you begin

To complete this tutorial, you'll need to be familiar with:

Source code

You can find the source code for this tutorial on Atlassian Bitbucket.

To clone the repository, run the following command:

1
git clone https://bitbucket.org/atlassian_tutorial/confluence-v2-query-tutorial.git

Alternatively, you can download the source as a ZIP archive.

This tutorial was last tested with Confluence 7.0 using Atlassian SDK 8.0.2.

Key elements

TitleQuery

The TitleQuery implements the SearchQuery interface. It takes an input string and uses it to construct a query against the search index. The method SearchQuery#expand expresses the logic using Confluence's built-in v2 queries.

In this case we want to return content with a title matching the given input or that has a prefix of the unstemmed title itself, or its parent, that matches the input.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TitleQuery implements SearchQuery {
    private static final String KEY = "titleQuery";
 
    private final String query;
 
    public TitleQuery(String query) {
        this.query = query;
    }
 
 ...
    @Override
    public SearchQuery expand() {
        return BooleanQuery.builder()
                .addShould(new QueryStringQuery(singletonList(SearchFieldNames.TITLE), query, BooleanOperator.OR))
                .addShould(new PrefixQuery(SearchFieldNames.CONTENT_NAME_UNSTEMMED_FIELD, query))
                .addShould(new PrefixQuery(SearchFieldNames.PARENT_TITLE_UNSTEMMED_FIELD, query))
                .build();
    }
}

SortBySpaceKey

SortBySpaceKey implements the SearchSort interface. The method SearchSort#expand specifies that we want to sort the result by space key, then content type, using Confluence's built-in v2 sort.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SortBySpaceKey implements SearchSort {
    private static final String KEY = "sortBySpaceKey";
 
    private final Order order;
 
    public SortBySpaceKey(Order order) {
        this.order = order;
    }
 
...
    @Override
    public Order getOrder() {
        return order;
    }
 
    @Override
    public SearchSort expand() {
        return new FieldSort(SearchFieldNames.SPACE_KEY, Type.STRING, order);
    }
}

SearchByTitleResource

This is a REST module that performs a search using the above query and sort. We execute a search using the v2 SearchManager which is injected into the REST module using the @ComponentImport annotation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Path("/search")
@Consumes(value = MediaType.APPLICATION_JSON)
@Produces(value = MediaType.APPLICATION_JSON)
public class SearchByTitleResource {
    private final SearchManager searchManager;
 
    @Autowired
    public SearchByTitleResource(@ComponentImport SearchManager searchManager) {
        this.searchManager = requireNonNull(searchManager);
    }
 
    @Path("/title")
    @GET
    public List<Map<String, String>> search(@QueryParam("query") String query) {
        SearchResults result;
        try {
            result = searchManager.search(new ContentSearch(
                    new TitleQuery(query),
                    new SortBySpaceKey(SearchSort.Order.ASCENDING),
                    SiteSearchPermissionsSearchFilter.getInstance(),
                    0, 10));
        } catch (InvalidSearchException e) {
            throw new RuntimeException(e);
        }
 
        List<Map<String, String>> response = new ArrayList<>();
        result.forEach(x ->
                response.add(ImmutableMap.of("title", x.getDisplayTitle(), "url", x.getUrlPath())));
 
        return response;
    }
 
}

We specify the root path for all REST modules of the plugin in atlassian-plugin.xml.

1
2
3
4
...
<rest key="titleSearch" path="/v2/search/query/tutorial" version="none">
</rest>
...

See how it works

Start a local Confluence instance

  1. Make sure you have saved all your code changes to this point.

  2. Open a Terminal and navigate to the plugin root folder (where the pom.xml file is stored).

  3. Run the following command:

    1
    atlas-run

    This command builds your plugin code, starts a Confluence instance, and installs your plugin. This may take a while. When the process is complete, you’ll see many status lines on your screen concluding with something like this:

    1
    2
    3
    [INFO] Confluence started successfully in 71s at http://localhost:1990/confluence
    [INFO] Type CTRL-D to shutdown gracefully
    [INFO] Type CTRL-C to exit

You can also build the plugin and deploy it into an existing Confluence instance.

Check the Rest API

Run the following command:

1
2
curl -u admin:admin -G "http://localhost:1990/confluence/v2/search/query/tutorial/title" \
--data-urlencode "query=confluence"

This will return any content with a title matching "confluence", sorted by space key.

Next steps

Learn more about extending Confluence's search capabilities with these tutorials:

Rate this page: