Searchkit V4: Search UI for Elasticsearch with Instantsearch

Joseph McElroy
Searchkit Blog
Published in
4 min readFeb 3, 2023

--

In previous versions of Searchkit, our architecture was tightly coupled to the UI and Elasticsearch, and we wanted to make it easier to build custom UIs. In Searchkit v3, by splitting concerns up with a GraphQL API in the middle, developers could build their own UIs and use Searchkit as an application layer.

However, we found that the GraphQL API itself became the bottleneck, and I found myself teaching developers how to use GraphQL, and how to build their own UIs. I wanted to make it easier for developers to get started with Searchkit, and to make it easier to build custom UIs. With GraphQL, the “getting started” journey become a lot more complicated, and was starting to become a blocker for adoption. The complexity just shifted from customising the UI to using the GraphQL API.

With Searchkit V4, we’re going back to Searchkit origins that made Searchkit popular in the first place, make it much easier to get started, but still be fully customisable.

Instantsearch Support

Searchkit V4 integrates with Algolia’s Instantsearch library, which is a Search UI library built by Algolia. Instantsearch is an amazing library, and it’s been used by many companies and supports many frameworks like React, Vue and Angular.

In recent years, companies like Typesense and MeiliSearch have emerged and adopted Instantsearch as their Search UI library. Searchkit follows that trend and chosen Instantsearch to provide the Search UI. Think of Searchkit as the adapter between Instantsearch and Elasticsearch.

See a demo of this in action!

You can start by simply using the CDN scripts and some inline scripts to get going.

<script src="https://cdn.jsdelivr.net/npm/@searchkit/instantsearch-client@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script>
<script src="https://cdn.jsdelivr.net/npm/searchkit@latest"></script>

<div id="searchbox" class="ais-SearchBox"></div>
<div id="hits"></div>
<div id="pagination"></div>

<script>
const searchkitClient = new Searchkit({
connection: {
host: "https://demo.es.us-east4.gcp.elastic-cloud.com:9243"
},
search_settings: {
highlight_attributes: ["title", "actors"],
search_attributes: ["title", "actors"],
result_attributes: ["title", "actors", "poster", "year"]
},
})
const search = instantsearch({
indexName: "search-movies",
searchClient: SearchkitInstantsearchClient(searchkitClient)
});

search.addWidgets([
instantsearch.widgets.searchBox({
container: "#searchbox"
}),
instantsearch.widgets.hits({
container: "#hits",
templates: {
item: `
<div>
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "title" }{{/helpers.highlight}}
</div>
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "actors" }{{/helpers.highlight}}
</div>
</div>
`
}
}),
instantsearch.widgets.pagination({
container: "#pagination"
})
]);

search.start();
</script>

Geo Search & Autocomplete Components Support

Not only Instantsearch but also supports Algolia’s Autocomplete library and geo search components. Quickly build an autocomplete UI or see your results on a map, all with Searchkit and Elasticsearch powering your results. See demo of this in action!

Geo search & filtering

const searchkitClient = new Searchkit({
connection: {
host: 'http://localhost:9200'
},
search_settings: {
result_attributes: ["text"],
search_attributes: [],
geo_attribute: "location"
}
})

const searchClient = Client(searchkitClient);

export default function Web() {
return (
<InstantSearch
indexName="my-geo-data"
searchClient={searchClient}
>
<div style={{ height: 500 }}>
<GoogleMapsLoader apiKey={apiKey} endpoint={endpoint}>
{(google) => (
<GeoSearch google={google}>
{({ hits }) => (
<>
{hits.map((hit) => (
<Marker key={hit.objectID} hit={hit} />
))}
</>
)}
</GeoSearch>
)}
</GoogleMapsLoader>

<div className="right-panel">
<Hits />
</div>

</div>
</InstantSearch>
);
}

This also helps customers who are using Algolia, but want to migrate to Elasticsearch. They can use Instantsearch to build their UI, and then migrate to Elasticsearch without having to rewrite their UI.

Powerful Elasticsearch Features Supported

With request hooks, you can customize the query before and after it is sent to Elasticsearch.

const results = await client.handleRequest(req.body, {
hooks: {
beforeSearch: (searchRequests) => {
const uiRequest = searchRequests[0]

return [
{
...uiRequest,
body: {
...uiRequest.body,
rescore: {
window_size: 100,
query: {
rescore_query: {
match: {
plot: {
query: uiRequest.body.query,
operator: "and",
},
},
},
query_weight: 1,
rescore_query_weight: 10,
}
}
}
},
searchRequests.slice(1, searchRequests.length)
]

},
}
});

Nested Fields Support

Searchkit also supports nested fields, allowing you to create a Search UI with parent-child models required for marketplace type searches.

{
facet_attributes: [
{
attribute: 'marketplace.supplier',
field: 'supplier.keyword',
type: 'string',
nestedPath: 'marketplace'
},
]
}

Searchkit Application Layer

Searchkit V2 would require direct access to Elasticsearch REST API which was a challenge due to security concerns with exposing Elasticsearch to the public internet. With Searchkit V4, we still allow this, but we’ve added support for the code to transition to the server-side, meaning we do not require Elasticsearch to be exposed to the public internet. It allows both scenarios to work.

import Client from '@searchkit/api'
import { NextApiRequest, NextApiResponse } from 'next'

const apiClient = Client(
{
connection: {
host: "https://demo.es.us-east4.gcp.elastic-cloud.com:9243"
},
search_settings: {
highlight_attributes: ["title", "actors"],
search_attributes: ["title", "actors"],
result_attributes: ["title", "actors", "poster", "year"]
}
},
{ debug: true }
)

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const results = await apiClient.handleRequest(req.body)
res.send(results)
}
Searchkit API Layer

If you look at the network request in the demo, its instantsearch based requests and @searchkit/api is transforming the request into elasticsearch queries.

This also provides a simpler path for upgrading Searchkit V2 applications. You should be able to switch to Searchkit V4 components without changing the way you access Elasticsearch.

When you’re ready to move to the server-side, you can use the @searchkit/api, deployed with Cloudflare Workers or Vercel Functions. This might sound complicated, but it’s actually very simple to setup.

You can learn more about this in this youtube video.

Getting Started

Visit the repo, read the quick start docs or checkout the demos. Theres also a youtube channel with Searchkit tutorials. More videos to come!

--

--