GithubHelp home page GithubHelp logo

searchkit / searchkit Goto Github PK

View Code? Open in Web Editor NEW
4.7K 88.0 442.0 87.25 MB

Search UI for Elasticsearch & Opensearch. Compatible with Algolia's Instantsearch and Autocomplete components. React & Vue support

Home Page: http://www.searchkit.co/docs

License: Apache License 2.0

JavaScript 3.76% TypeScript 45.07% CSS 9.00% MDX 39.20% Jupyter Notebook 2.97%
elasticsearch react search ui-components javascript ui nodejs typescript components vue

searchkit's Introduction

Elasticsearch Search UI Components

Searchkit is an open source library which helps you build a great search experience with Elasticsearch. Works with Javascript, React, Vue, Angular, and more.

npm version Discord Shield

Website | Demos | Documentation | Discord

Alt Text

Searchkit provides a Search UI for Elasticsearch or Opensearch. With Searchkit, you can use Instantsearch components like Searchbox, refinement filters and results (and many more!) to build a search experience.

Searchkit is great for anyone who want to build a search experience quickly.

Searchkit simplifies Search UI with Elasticsearch:

  • UI Search Components for React, Vue, Angular, and more
  • Searchkit Node API proxies Elasticsearch requests from the browser.
  • Ability to use Elasticsearch Query DSL for advanced queries

Demos

Quick Start Guides

Tutorials

Codesandbox Examples

Code Examples (on Github)

Proxy Elasticsearch Quick Starts

Video Tutorials

Or checkout our documentation for more examples.

Installation

Either install via npm or yarn

npm install searchkit @searchkit/api @searchkit/instantsearch-client

or via CDN

<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>

Setup Elasticsearch

Searchkit requires Elasticsearch 7.0 or higher or Opensearch 2.4 or higher.

Below we are using Docker to run Elasticsearch.

docker pull docker.elastic.co/elasticsearch/elasticsearch:8.6.2
docker network create elastic
docker run --name elasticsearch --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" -e http.cors.enabled=true -e "http.cors.allow-origin='*'" -e http.cors.allow-headers=X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization -e http.cors.allow-credentials=true -e network.publish_host=localhost -e xpack.security.enabled=false docker.elastic.co/elasticsearch/elasticsearch:8.6.2

then lets add an index and some data

curl --location --request PUT 'http://localhost:9200/products' \
--header 'Content-Type: application/json' \
--data-raw '{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "description": {
        "type": "text"
      },
      "price": {
        "type": "integer"
      },
      "categories": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}'

curl --location --request POST 'http://localhost:9200/products/_doc' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "Apple iPhone 12 Pro Max",
  "description": "The iPhone 12 Pro Max is the most powerful iPhone ever. It has a 6.7-inch Super Retina XDR display, a Ceramic Shield front cover, and a triple-camera system with a LiDAR scanner. It also has a 5G connection, a 6-core CPU, and a 4-core GPU. The iPhone 12 Pro Max is available in 128GB, 256GB, and 512GB storage options.",
  "categories": ["phones", "apple"],
  "price": 800
}'
 
curl --location --request POST 'http://localhost:9200/products/_doc' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "Apple iPhone 12 Pro",
  "description": "The iPhone 12 Pro is the most powerful iPhone ever. It has a 6.1-inch Super Retina XDR display, a Ceramic Shield front cover, and a triple-camera system with a LiDAR scanner. It also has a 5G connection, a 6-core CPU, and a 4-core GPU. The iPhone 12 Pro is available in 128GB, 256GB, and 512GB storage options.",
  "categories": ["phones", "apple"],
  "price": 700
}'

Setup Searchkit

Searchkit compatible with all Instantsearch frameworks. Below is an example using react-instantsearch.

import Searchkit from "searchkit"
import Client from '@searchkit/instantsearch-client'

// import your InstantSearch components
import { InstantSearch, SearchBox, Hits, RefinementList, Pagination, RangeInput } from 'react-instantsearch';

const sk = new Searchkit({
  connection: {
    host: 'http://localhost:9200',
    // with an apiKey
    // https://www.searchkit.co/docs/guides/setup-elasticsearch#connecting-with-api-key
    // apiKey: '##########'
    // with a username/password
    // https://www.searchkit.co/docs/guides/setup-elasticsearch#connecting-with-usernamepassword
    //auth: {
    //  username: "elastic",
    //  password: "changeme"
    //}
  },
  search_settings: {
    search_attributes: [{ field: 'title', weight: 3 }, 'actors', 'plot'],
    result_attributes: ['title', 'actors', 'poster', 'plot'],
    highlight_attributes: ['title'],
    facet_attributes: [
      { attribute: 'actors', field: 'actors.keyword', type: 'string' },
      { attribute: 'imdbrating', type: 'numeric', field: 'imdbrating' }
    ]
  }
})

const searchClient = Client(sk);

const App = () => (
  <InstantSearch
    indexName="imdb_movies"
    searchClient={searchClient}
  >
    <SearchBox />
    <div className="left-panel">
      <RefinementList attribute="actors" searchable={true} limit={10} />
      <RangeInput attribute="imdbrating" />
    </div>
    <div className="right-panel">
      <Hits />
      <Pagination />
    </div>
  </InstantSearch>
}

follow along with the Getting Started guide.

Hide Elasticsearch from the browser

Searchkit Node API allows you to proxy requests to Elasticsearch from the browser. This is useful if you want to hide Elasticsearch from the browser, or if you want to add user permission filters to the query.

Query Customisation

Searchkit has an out the box query builder, but you can also customise the query by passing a getQuery function to the apiClient.

const results = await apiClient.handleRequest(req.body, {
  getQuery: (query, search_attributes) => {
    return [
      {
        combined_fields: {
          query,
          fields: search_attributes,
        },
      },
    ];
  },
});

Semantic Query Search

Searchkit supports KNN query search. Below is an example of a KNN query search.

  const results = await client.handleRequest(req.body, {
    getKnnQuery(query, search_attributes, config) {
      return {
        field: 'dense-vector-field',
        k: 10,
        num_candidates: 100,
        // supported in latest version of Elasticsearch
        query_vector_builder: { 
          text_embedding: {
            model_id: 'cookie_model',
            model_text: query
          }
        }
      }
    }
  });

Follow along with the Semantic Search tutorial.

Advanced Customisation

You can also override the entire query with request hooks. Below is an example of a request hook that adds a rescore query to the first search request.

You can apply this at beforeSearch and afterSearch.

  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)
        ]
        
      },
    }
  });

read more in the api docs here.

Query Rules

Query rules allows you to customize the behavior of the search experience. You can use query rules to boost or filter results, or to change the ranking of results, based on a set of conditions.

Below is an example of a query rule that boosts results for movies with Dan Aykroyd or Charlie Sheen, and filters results to only show movies if the query is the word "movie".

{
  id: '1',
  conditions: [
    [
      {
        context: 'query',
        value: 'movie',
        match_type: 'exact'
      }
    ]
  ],
  actions: [
    {
      action: 'QueryBoost',
      query: 'actors:"Dan Aykroyd" OR actors:"Charlie Sheen"',
      weight: 2
    },
    {
      action: 'QueryFilter',
      query: 'type:"movie"'
    }
  ]
}

read more at Query Rules docs.

NPM Packages

FAQ

Q: Do I need to expose Elasticsearch to the public internet?

Searchkit proxies requests to Elasticsearch.

Searchkit offers both options, either perform the search directly from the browser, or use the Searchkit API to proxy requests to Elasticsearch. Directly from the browser offers great developer experience & prototyping. Once you are ready to deploy, you can use the Searchkit API to proxy requests to Elasticsearch.

Q: Do I need to use React?

You can use React, React Native, Vue, Angular. You dont even need to use a frontend framework, you can use plain Javascript and HTML with instantsearch.js widgets.

Q: Which version of Elasticsearch is supported?

Searchkit is compatible with Elasticsearch 7.0 and above + Opensearch 2.0 and above.

Q: Do you support Android and iOS?

Potentially. Searchkit API mimics the Algolia API, so it should be possible to use the Algolia Instantsearch client with Searchkit API with a few tweaks. If you are interested in this, please let us know.

Q: Why would I use Searchkit instead of Algolia?

Elasticsearch has alot of advantages over Algolia. You might want to use Elasticsearch as a cheaper alternative to Algolia, especially if you have a large dataset. You might want to run Elasticsearch on your own infrastructure, or have greater control over the query relevance.

searchkit's People

Contributors

a-magdy avatar bcruddy avatar carlyrichmond avatar danieljuhl avatar davireis avatar dependabot[bot] avatar falnyr avatar fetten avatar gregorypotdevin avatar infacq avatar joemcelroy avatar kud avatar mattsurabian avatar mcmanning avatar mcs07 avatar megastef avatar mking avatar nchevobbe avatar olf avatar pahan35 avatar pixcai avatar ppearcy avatar pranavp10 avatar srghma avatar ssetem avatar tristanreid avatar vincentfretin avatar vladimir-tikhonov avatar weisisheng avatar wwwillchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

searchkit's Issues

Add a Date Filter

I haven't tried fooling around with date fields and the current filters, but date field support could make sense in :

  • Menu (with the possibilité to set the format and filter on just year, or year/month, etc.)
  • Hierarchical Menu (year, then month, etc.)
  • Range Filter

Other possibilities include having a small calendar to pick a date, or 2 to pick a range.

Option to not search immediately

  • An option within searchkitManager to not search immediately
  • Will only render results from ES once the user is querying (via searchbox for example
  • initial loading view is shown instead

Pagination should use links

Similar to bootstrap's pager, if the pagination buttons were links, you could right-click the link to open the new page in another tab.

Avoid redondant searches

When moving around the slider in RangeFilter and releasing the slider at the same position it previously was, a new search request is launched.

NumericRefinementListFilter isn't hidden when there are no buckets

Other facets disappear when they have no contents. NumericRefinementListFilter still displays the facet's title. Can be seen in the demo, the "Length" title is displayed while loading the results.

Requires adding a disabled css state link in RefinementListFilter

Add optional inputs for RangeFilter and NumericRefinementList

Sometimes you want the user to be able to put specific values easily, having inputs helps :
image

This could be a showInputs attribute on RangeFilter and/or NumericRefinementList, but it could also be a nice to have a standalone RangeInputFilter, I guess.

Scroll results to top on pagination change

The current code uses window.scrollTo(0,0), but the demo has a scrolling layout__results.
A "scrollResultsToTop" event should probably be triggered to let the corresponding component react to it.

componentWillUnmount should remove the accessor

The accessor is added to searchkit on componentWillMount but isn't removed on componentWillUnmount. This prevents from having "dynamic" filter lists with simple/advanced modes that disable/enable filters.

Filter Selected Conditional Component

A component that wraps filter components and shows only when the conditional is satisfied:

 <ShowWhenSelected filterId="type" value="Documents">
   <RefinementFilter ... />
</ShowWhenSelected>

FacetAccessor with different key/field values

The current FacetAccessor passes the same key to build a TermsBucket : TermsBucket(this.key, this.key, ...)
This doesn't allow to have multiple facets using the same field as they'll all share the same bucket key and collide.

An optional aggId option (please find a suitable name...) could be used to allow multiple facets on the same field.

InitialView component

Currently Hits component is responsible for initialView ( view shown when no response have been returned from ES yet )

Should be in its own component like NoHits component.

  • InitialLoading Component
  • Unit tests
  • documentation

Caching of queries

Maybe something like this would be enough?

this.cache = {}

if (this.cache[query] !== undefined)
  return this.cache[query]

this.cache[query] = response

Advanced filter type UI for searchkit

Is it possible to create a UI similar to react-redux-test demo where filters can be added based on predefined keywords.

For example,
if the following 3 keywords are defined for searching,

  1. Age
  2. Location
  3. Price

The user will be able to add a new filter below the main search box.

Also, it should support range input for fields like age, price (number field), (ability to show custom input types) when a new filter is added.

Searchkit Themes

  • Being able to skin to various themes (material, minimal)
  • Clean up component styles, only basic level layout
  • Better basic default layout

Bug in pagination due to accessors array position

When PageSizeAccessor appears after the PaginationAccessor, the latter will pick up 20 as the page size (because it's 0 before PageSizeAccessor steps in) instead of what's specified in PageSizeAccessor.

In Chrome console, at stack trace:

PaginationAccessor.buildOwnQuery (PaginationAccessor.js:20)
(anonymous function) (Searcher.js:30)
arrayReduce (index.js:1450)
(anonymous function) (index.js:3445)
Searcher.buildQuery (Searcher.js:29)
(anonymous function) (SearcherCollection.js:40)
arrayEach (index.js:1289)
(anonymous function) (index.js:3345)
SearcherCollection.buildQuery (SearcherCollection.js:40)
SearchkitManager.buildQuery (SearchkitManager.js:55)
SearchkitManager._search (SearchkitManager.js:97)
SearchkitManager.performSearch (SearchkitManager.js:85)
Pagination.setPage (Pagination.js:48)
React.cloneElement.onMouseDown (FastClick.js:17)
ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:71)
executeDispatch (EventPluginUtils.js:79)
executeDispatchesInOrder (EventPluginUtils.js:102)
executeDispatchesAndRelease (EventPluginHub.js:43)
executeDispatchesAndReleaseTopLevel (EventPluginHub.js:54)
forEachAccumulated (forEachAccumulated.js:23)
EventPluginHub.processEventQueue (EventPluginHub.js:259)
runEventQueueInBatch (ReactEventEmitterMixin.js:18)
ReactEventEmitterMixin.handleTopLevel (ReactEventEmitterMixin.js:34)
handleTopLevelWithoutPath (ReactEventListener.js:93)
handleTopLevelImpl (ReactEventListener.js:73)
Mixin.perform (Transaction.js:136)
ReactDefaultBatchingStrategy.batchedUpdates (ReactDefaultBat…Strategy.js:62)
batchedUpdates (ReactUpdates.js:94)
ReactEventListener.dispatchEvent (ReactEventListener.js:204)
> this.accessors
> [SearchAccessor, SortingAccessor, FacetAccessor, FacetAccessor, FacetAccessor, FacetAccessor, NumericOptionsAccessor, FacetAccessor, PaginationAccessor, PageSizeAccessor]

and also at that point

> _.reduce(this.accessors, function(query, accessor) { console.log('query page size', query.query.size);return accessor.buildOwnQuery(query);}, query)

gives:

(10 times) query page size 0

Pagination pages

  • Show pages as options to select from
  • Unit tests
  • Documentation

Build custom queries

Hi there

First of all thnx for this awesome component!

I still have a few questions that i can't figure out :(
How can i build own custom queries in my React components? For ex. (minified query)

{
  "query": {
    "filtered": {
      "query": {
        "match": {
          "language": "nl-BE"
        }
      },
      "filter": {
        "and": [
          {
            "geo_distance": {
              "distance": "25km",
              ...
            }
          }
        ]
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
      }
    }
  ]
}

I'm currently looking at the "ImmutableQuery" object that i then assign the the "SearchkitManager" but without any results.

Thnx in advance!

SearchBox query throttling doesn't work

When SearchBox's onChange method is called, the following code is used to generate a new search :

            throttle(()=> {
                this.searchQuery(this.accessor.getQueryString())
            }, 400)()

A new throttled searchQuery function is generated each time, so they just stack up without waiting for the 400ms delay. The throttle function should be created in the constructor or in componentWillMount and reused for every call.

Searchkit can be decoupled from ElasticSearch?

Hi,

I really like how searchkit works, but right now i have some REST api of products that i would like to make a front with searchkit but ElasticSearch is not an option for me.

It can be decoupled from ElasticSearch? or at least "intercept" with some proxy the calls to ElasticSearch to another component that has the Data?

Thanks

Introduce purerender utility

we need to add utility to shallowCompare objects and ignore functions except from /component^/i

and provide annotation helpers, perhaps a React.Component subclass too

  • shallowCompare utils
  • annotation/decorator
  • class based
  • unit tests
  • use where appropriate

Error Handling

  • Error states for Hits if error response
  • timeout states

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.