# Custom search service

> For the complete documentation index, see [llms.txt](https://www.jetbrains.com/help/writerside/llms.txt).

As an alternative to [using Algolia](configure-search.html), you can configure your help website to query a custom endpoint where you can host your own search service.

Procedure: Configure search endpoint

1. In your documentation project, open  `[buildprofiles.xml](buildprofiles-xml.html)`  or create it if you do not have it yet.

2. Under the `<variables>` tag, specify the URL to the search service in `<search-endpoint>`. For example:

```XML
<buildprofiles xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/build-profiles.xsd"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <variables>
        <search-endpoint>https://my.search/endpoint</search-endpoint>
    </variables>
</buildprofiles>
```

Now when you build your help and publish it, the search field will query the specified endpoint. The endpoint must accept [requests](#request_format) and send back [responses](#response_format) in a specific format.

In the built artifacts, open `config.json` and check the `searchService` and `searchServiceUrl` keys. The search service URL should contain the specified endpoint followed by `/preview-search`, the name of the project root directory, and the ID of the help instance. For example:

```JSON
searchService: "custom"
searchServiceUrl: "https://my.search/endpoint/preview-search/my-docs/hi"
```

## Request format

When a user types something in the search field, the help application sends a request to the specified search service URL with parameters of the search query. Here is an example search query:

```HTTP_REQUEST_FULL
https://my.search/endpoint/preview-search/my-docs/hi?isExactSearch=false&maxHits=25&query=hello
```

So the request mapping should be for `/preview-search/{1}/{2}`, where `{1}` is the documentation project root directory and `{2}` is the ID of the help instance. You can use these path variables to process search requests for multiple published help instances from the same endpoint.

The request parameters are:

`query`
: Specifies the text to search for.

`isExactSearch`
: Specifies whether search should take various forms of words into account.

`maxHits`
: Specifies the maximum number of results to return.

The search service must process this request and [return the search query results as a JSON object](#response_format).

## Response format

The response entity must be an HTTP 200 OK response with a JSON object that consists of the `hits` field that holds an array of search hits.

```JSON
{
    "hits": [
        {
            "url": "https://my.docs.com/product/getting-started.html",
            "pageTitle": "Getting Started",
            "breadcrumbs": "Intro|Getting Started",
            "mainTitle": "Getting Started",
            "objectID": "my_docs_product_getting_started.html",
            "_snippetResult": {
                "content": {
                    "value": "Here is something to get started",
                    "matchLevel": "full"
                }
            },
            "_highlightResult": {
                "headings": {
                    "value": "Here is something to get started",
                    "matchLevel": "none",
                    "matchedWords": [
                        "hello"
                    ]
                },
                "content": {
                    "value": "Here is something to get started",
                    "matchLevel": "full",
                    "fullyHighlighted": false,
                    "matchedWords": [
                        "hello"
                    ]
                },
                "pageTitle": {
                    "value": "Getting Started",
                    "matchLevel": "none",
                    "matchedWords": []
                },
                "metaDescription": {
                    "value": "",
                    "matchLevel": "none",
                    "matchedWords": []
                },
                "breadcrumbs": {
                    "value": "Intro|Getting Started",
                    "matchLevel": "none",
                    "matchedWords": []
                },
                "mainTitle": {
                    "value": "Getting Started",
                    "matchLevel": "none",
                    "matchedWords": []
                }
            }
        }
    ],
    "nbHits": 1,
    "page": 0,
    "nbPages": 1,
    "hitsPerPage": 25,
    "query": "hello",
    "queryID": "3e3d57a27d66323ad411a561ce35bb78"
}
```

This JSON contains everything the help application needs to render search results: page title, URL, breadcrumbs, the snippet to show, and the words to highlight.

## Sample search service

We provide our implementation of the search service in the form of a JAR file that runs a Spring Boot application. The application exposes a search endpoint that can accept [requests](#request_format) and sends back correct [responses](#response_format). It can use Algolia indexes produced by the Writerside builder to process search requests.

Procedure: Run search service with no index

1. Download [writerside-search-1.0.jar](https://packages.jetbrains.team/files/p/writerside/search-service/writerside-search-1.0.jar).

2. Run the following command to start the service without any search indexes:

```SHELL
java -jar writerside-search-1.0.jar run
```

In the console, you should see the standard Spring Boot output followed by:

```PLAINTEXT
Created controller with engine TFIDF
algoliaIndexPath =
tfidfIndexPath =
```

3. Send a request to the created endpoint to test the service: [http://127.0.0.1:8080/preview-search/foo/bar?isExactSearch=false&query=test](http://127.0.0.1:8080/preview-search/foo/bar?isExactSearch=false&query=test)

The response should return zero hits because there is no search index to query against:

```PLAINTEXT
{"nbHits":0,"queryID":"e6e726f8-ebce-4296-ad9c-de8ee4bd3543","hits":[]}
```

Procedure: Run search service with index

1. Build your documentation website with the [Docker builder](build-with-docker.html). Besides the ZIP archive with the built help website, it also produces a ZIP archive with Algolia indexes, for example: `algolia-indexes-HI.zip`. Unpack the archive with Algolia indexes and make sure that it contains JSON files with the content from your help website.

2. Specify the path to the directory with Algolia indexes when running the search service:

```SHELL
java -jar writerside-search-1.0.jar run --algolia-indexes=/path/to/algolia-indexes-HI/
```

This time, you will see the following output:

```PLAINTEXT
Created controller with engine TFIDF
algoliaIndexPath = algolia-indexes-HI
tfidfIndexPath =
```

Now, if you query the service at [http://127.0.0.1:8080/preview-search/foo/bar?isExactSearch=false&query=test](http://127.0.0.1:8080/preview-search/foo/bar?isExactSearch=false&query=test), it will return results for "test" based on the specified indexes. So if your help has the word "test" somewhere, there will be some search hits with this word in the content, title, or page name.

> **Note:**
> In the examples above, we are querying against `/preview-search/foo/bar`, while the built help will have the name of the [help module](projects.html#help_module) and [instance](instances.html) in the URL instead of `foo` and `bar`. Our sample search service ignores the values after `/preview-search` in the URL, because it hosts just one search index that you specify when starting the service. You can test the running service with any values, but they must be present.

If you want the search field in your help website to query the custom search service, [set the search endpoint](#configure-search-endpoint) in  `[buildprofiles.xml](buildprofiles-xml.html)`  in your documentation project. For example, if you are hosting the website on the same machine where the search service is running:

```XML
<search-endpoint>http://127.0.0.1/8080</search-endpoint>
```

Otherwise, you need to specify the IP address of the machine where the search service is running. The exposed search endpoint must be accessible from the machine that will serve your published help website.

> **Note:**
> By default, the search service runs on port 8080. You can set a different port number using the `server.port` parameter, for example:
>
>
> ```SHELL
> java -Dserver.port=1234 -jar writerside-search-1.0.jar run
> ```

