Адаптер для использования потрясающей библиотеки Instantsearch.js с поисковым сервером Typesense для создания многофункциональных поисковых интерфейсов.
Вот пример пользовательского интерфейса, который вы можете создать с помощью этого адаптера: song-search.typesense.org.
Примечание. Если ваш интерфейс поиска построен на основе пользовательского компонента автозаполнения или основан на @algolia/autocomplete-js, вам не нужен этот адаптер для его использования с Typesense, поскольку библиотека typesense-js уже поддерживает выборку на стороне клиента. данные из любых асинхронных источников данных. Подробнее читайте здесь.
Хорошие ребята из Algolia создали и открыли исходный код Instantsearch.js, который представляет собой набор готовых компонентов, которые вы можете использовать для быстрого создания интерактивного поиска.
С адаптером в этом репозитории вы сможете использовать Instantsearch (и его родственники React, Vue и Angular) с данными, индексированными на поисковом сервере Typesense.
Если вы раньше не использовали Instantsearch, мы рекомендуем ознакомиться с руководством по началу работы здесь. Прочитав руководство, следуйте инструкциям ниже, чтобы подключить адаптер Typesense к Instantsearch.
Вот руководство по созданию интерфейса быстрого поиска с помощью Typesense и InstantSearch.js: https://typesense.org/docs/0.20.0/guide/search-ui-comComponents.html.
Вот демонстрационное стартовое приложение, которое покажет вам, как использовать адаптер: https://github.com/typesense/typesense-instantsearch-demo.
$ npm install --save typesense-instantsearch-adapter @babel/runtime
или
$ yarn add typesense-instantsearch-adapter @babel/runtime
или вы также можете напрямую включить адаптер через тег сценария в свой HTML:
< script src =" https://cdn.jsdelivr.net/npm/typesense-instantsearch-adapter@2/dist/typesense-instantsearch-adapter.min.js " > </ script >
<!-- You might want to pin the version of the adapter used if you don't want to always receive the latest minor version -->
Поскольку это адаптер, он не установит библиотеку Instantsearch автоматически. Вам необходимо установить одно из следующих компонентов непосредственно в ваше приложение:
Информацию о том, как начать работу с каждой из вышеперечисленных библиотек, вы найдете в соответствующих репозиториях.
Мы также рекомендуем воспользоваться create-instantsearch-app, чтобы создать пользовательский интерфейс поиска на основе стартового шаблона.
import instantsearch from "instantsearch.js" ;
import { searchBox , hits } from "instantsearch.js/es/widgets" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : "8108" ,
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
const search = instantsearch ( {
searchClient ,
indexName : "products" ,
} ) ;
search . addWidgets ( [
searchBox ( {
container : "#searchbox" ,
} ) ,
hits ( {
container : "#hits" ,
templates : {
item : `
<div class="hit-name">
{{#helpers.highlight}}{ "attribute": "name" }{{/helpers.highlight}}
</div>
` ,
} ,
} ) ,
] ) ;
search . start ( ) ;
Сюда можно добавить любые виджеты Instantsearch, поддерживаемые адаптером.
Вы также найдете рабочий пример в test/support/testground. Чтобы запустить его, запустите npm run testground
из корневой папки проекта.
import React from "react" ;
import ReactDOM from "react-dom" ;
import { SearchBox } from "react-instantsearch-dom" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
const App = ( ) => (
< InstantSearch indexName = "products" searchClient = { searchClient } >
< SearchBox / >
< Hits / >
< / InstantSearch >
) ;
Затем вы можете добавить сюда любые виджеты Instantsearch-React, которые поддерживаются адаптером.
Приведенные выше инструкции также применимы к React Native.
App.vue:
< template >
< ais-instant-search :search-client = " searchClient " index-name = " products " >
< ais-search-box />
< ais-hits >
< div slot = " item " slot-scope = " { item } " >
< h2 >{{ item.name }}</ h2 >
</ div >
</ ais-hits >
</ ais-instant-search >
</ template >
< script >
import TypesenseInstantSearchAdapter from " typesense-instantsearch-adapter " ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ({
server : {
apiKey : " abcd " , // Be sure to use an API key that only allows search operations
nodes : [
{
host : " localhost " ,
path : " " , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : " 8108 " ,
protocol : " http " ,
},
],
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
},
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : " name,description,categories " ,
},
});
const searchClient = typesenseInstantsearchAdapter . searchClient ;
export default {
data () {
return {
searchClient,
};
},
};
</ script >
Затем вы можете добавить сюда любые виджеты Instantsearch, которые поддерживаются адаптером.
// app.component.ts
import { Component } from "@angular/core" ;
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter" ;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [
{
host : "localhost" ,
path : "" , // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
port : "8108" ,
protocol : "http" ,
} ,
] ,
cacheSearchResultsForSeconds : 2 * 60 , // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
} ,
// The following parameters are directly passed to Typesense's search API endpoint.
// So you can pass any parameters supported by the search endpoint below.
// query_by is required.
additionalSearchParameters : {
query_by : "name,description,categories" ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
@ Component ( {
selector : "app-root" ,
templateUrl : "./app.component.html" ,
styleUrls : [ "./app.component.css" ] ,
} )
export class AppComponent {
config = {
indexName : "products" ,
searchClient ,
} ;
}
Затем вы можете добавить сюда любые виджеты Instantsearch, которые поддерживаются адаптером.
hierarchicalMenu
Для этого виджета вы хотите создать независимые поля в схеме коллекции со следующим соглашением об именах:
field.lvl0
field.lvl1
field.lvl2
для вложенной иерархии field.lvl0 > field.lvl1 > field.lvl2
Каждое из этих полей также может содержать массив значений. Это полезно для обработки нескольких иерархий.
sortBy
При создании экземпляра этого виджета вы хотите установить значение имени индекса в следующем формате:
search . addWidgets ( [
sortBy ( {
container : "#sort-by" ,
items : [
{ label : "Default" , value : "products" } ,
{ label : "Price (asc)" , value : "products/sort/price:asc" } ,
{ label : "Price (desc)" , value : "products/sort/price:desc" } ,
] ,
} ) ,
] ) ;
Обобщенный шаблон для атрибута значения: <index_name>[/sort/<sort_by>]
. Адаптер будет использовать значение в <sort_by>
в качестве значения параметра поиска sort_by
.
configure
Если вам нужно указать параметр поиска filter_by
для Typesense, вы хотите использовать виджет configure
InstantSearch вместе с facetFilters
, numericFilters
или filters
.
Формат facetFilters
и numericFilters
такой же, как в Algolia, описанный здесь. Но filters
должны быть в формате filter_by
Typesense, как описано в этой таблице.
Установка filter_by
внутри конфигурации additionalQueryParameters
работает только при первоначальной загрузке виджетов, поскольку InstantSearch впоследствии внутренне переопределяет поле filter_by
. Подробнее читайте здесь.
index
Для федеративного/многоиндексного поиска вам потребуется использовать виджет index
. Чтобы затем иметь возможность указать разные параметры поиска для каждого индекса/коллекции, вы можете указать их с помощью конфигурации collectionSpecificSearchParameters
:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "abcd" , // Be sure to use an API key that only allows search operations
nodes : [ { host : "localhost" , path : "/" , port : "8108" , protocol : "http" } ] ,
} ,
// Search parameters that are common to all collections/indices go here:
additionalSearchParameters : {
numTypos : 3 ,
} ,
// Search parameters that need to be *overridden* on a per-collection-basis go here:
collectionSpecificSearchParameters : {
products : {
query_by : "name,description,categories" ,
} ,
brands : {
query_by : "name" ,
} ,
} ,
} ) ;
const searchClient = typesenseInstantsearchAdapter . searchClient ;
По сути, любые параметры, установленные в collectionSpecificSearchParameters
будут объединены со значениями в additionalSearchParameters
при запросе Typesense, эффективно переопределяя значения в additionalSearchParameters
для каждой коллекции.
geoSearch
Algolia по умолчанию использует _geoloc
для имени поля, в котором хранятся значения широты для записи. В Typesense вы можете назвать поле географического местоположения как угодно. Если вы используете имя, отличное от _geoloc
, вам необходимо указать его при инициализации адаптера, как показано ниже, чтобы InstantSearch мог получить к нему доступ:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
geoLocationField : "lat_lng_field" , // <<======
additionalSearchParameters ,
} ) ;
dynamicWidgets
Доступно начиная с Typesense Server
v0.25.0.rc12
Этот виджет dynamicWidgets
работает сразу после установки без каких-либо дополнительных изменений, но если вы хотите контролировать порядок, в котором эти фасеты отображаются в пользовательском интерфейсе, Instantsearch ожидает, что будет установлен параметр renderingContent
.
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
renderingContent : {
// <<===== Add this, only if you want to control the order of the widgets displayed by dynamicWidgets
facetOrdering : {
facets : {
order : [ "size" , "brand" ] , // <<===== Change this as needed
} ,
} ,
} ,
additionalSearchParameters ,
} ) ;
Подробнее обо всех доступных вариантах renderingContent
читайте в документации Algolia здесь.
Доступно начиная с typeense-instantsearch-adapter
2.7.0-2
Если какие-либо строковые поля в ваших документах имеют двоеточие :
в своих значениях (например, скажем, есть поле с именем { brand: "a:b" }
, тогда вам нужно будет добавить параметр, как показано ниже, при создании экземпляра адаптера:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetableFieldsWithSpecialCharacters : [ "brand" ] , // <======= Add string fields that have colons in their values here, to aid in parsing
additionalSearchParameters ,
} ) ;
Если какие-либо числовые имена полей в ваших документах содержат специальные символы, такие как >
, <
, =
(например, допустим, есть поле с именем { price>discount: 3.0 }
), тогда вам нужно будет добавить параметр, как показано ниже, при создании экземпляра адаптера:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetableFieldsWithSpecialCharacters : [ "price>discount" ] , // // <======= Add numeric fields that have >, < or = in their names, to aid in parsing
additionalSearchParameters ,
} ) ;
facet_by
Доступно начиная с typesense-instantsearch-adapter
2.8.0-1
и Typesense Serverv0.26.0.rc25
Параметр facet_by
управляется внутри InstantSearch при использовании различных виджетов фильтров.
Но если вам нужно передать пользовательские параметры в параметр facet_by
(например, параметры сортировки на стороне сервера), вы можете использовать параметр facetByOptions
, как показано ниже:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
facetByOptions : {
brand : "(sort_by: _alpha:asc)" ,
category : "(sort_by: _alpha:desc)" ,
} , // <======= Add any facet_by parameter as a key value pair. Don't forget the surrounding parantheses in the value.
collectionSpecificFacetByOptions : {
collection1 : {
brand : "(sort_by: _alpha:desc)" ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override facetByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Обратите внимание, что для сортировки в уточненных списках, помимо сортировки на стороне сервера Typesense, вам также необходимо передать параметр sortBy
виджету уточнения, чтобы также соответствующим образом отсортировать результаты на стороне клиента.
filter_by
Доступно начиная с typeense-instantsearch-adapter
2.8.0-5
Параметр filter_by
управляется внутри InstantSearch при использовании различных виджетов фильтров.
По умолчанию адаптер использует точную фильтрацию ( filter_by: field:=value
) при отправке запросов в Typesense. Если вам нужно настроить адаптер для использования :
(неточная фильтрация на уровне слов — filter_by: field:value
), вы хотите создать экземпляр адаптера, используя конфигурацию filterByOptions
:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
filterByOptions : {
brand : { exactMatch : false } , // <========== Add this to do non-exact word-level filtering
category : { exactMatch : false } ,
} ,
collectionSpecificFilterByOptions : {
collection1 : {
brand : { exactMatch : false } ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override filterByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Доступно начиная с typeense-instantsearch-adapter
2.9.0-0
Вот способ отключить переопределения/правила курирования, когда пользователи выбирают определенный порядок сортировки:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
sortByOptions : {
"field1:desc,field2:desc" : { enable_overrides : false } , // <========== Add this to disable sorting when this particular Typesense `sort_by` string is generated by the sortBy widget
} ,
collectionSpecificSortByOptions : {
collection2 : {
"field1:desc,field2:desc" : { enable_overrides : false } ,
} ,
} , // <======= Use this parameter if multiple collections share the same field names, and you want to use different options for each field. This will override sortByOptions for that particular collection.
additionalSearchParameters ,
} ) ;
Если у вас есть виджеты sortBy, настроенные со значением indexName products/sort/price:asc
, например, то ключ внутри sortByOptions
должен быть price:asc
.
Доступно начиная с typeense-instantsearch-adapter
2.7.1-4
По умолчанию, когда в качестве параметров поиска используется group_by
, адаптер объединяет результаты по всем группам в единый список последовательных совпадений.
Если вы хотите сохранить группы, вам нужно установить flattenGroupedHits: false
при создании экземпляра адаптера.
Это поместит первое попадание в группу в качестве основного попадания, а затем добавит все попадания в группе внутри ключа _grouped_hits
внутри каждого попадания.
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
flattenGroupedHits : false , // <=======
additionalSearchParameters ,
} ) ;
Доступно начиная с typeense-instantsearch-adapter
2.7.0-3
Общая идея состоит в том, чтобы сначала подключиться к жизненному циклу запроса Instantsearch, перехватить типизированный запрос и отправить его в API внедрения, получить внедрения, а затем отправить векторы в Typesense для выполнения поиска векторов ближайшего соседа.
Вот демо-версия, которую вы можете запустить локально, чтобы увидеть это в действии: https://github.com/typesense/showcase-hn-comments-semantic-search.
Вот как это сделать в Instantsearch.js:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
additionalSearchParameters ,
} ) ;
// from https://github.com/typesense/showcase-hn-comments-semantic-search/blob/8a33006cae58b425c53f56a64e1273e808cd9375/src/js/index.js#L101
const searchClient = typesenseInstantsearchAdapter . searchClient ;
search = instantsearch ( {
searchClient ,
indexName : INDEX_NAME ,
routing : true ,
async searchFunction ( helper ) {
// This fetches 200 (nearest neighbor) results for semantic / hybrid search
let query = helper . getQuery ( ) . query ;
const page = helper . getPage ( ) ; // Retrieve the current page
if ( query !== "" && [ "semantic" , "hybrid" ] . includes ( $ ( "#search-type-select" ) . val ( ) ) ) {
console . log ( helper . getQuery ( ) . query ) ;
helper
. setQueryParameter (
"typesenseVectorQuery" , // <=== Special parameter that only works in [email protected] and above
`embedding:([], k:200)` ,
)
. setPage ( page )
. search ( ) ;
console . log ( helper . getQuery ( ) . query ) ;
} else {
helper . setQueryParameter ( "typesenseVectorQuery" , null ) . setPage ( page ) . search ( ) ;
}
} ,
} ) ;
Существует два режима кэширования:
Кэширование на стороне сервера:
Чтобы включить кэширование на стороне сервера, добавьте параметр useServerSideSearchCache: true
в блок конфигурации server
typeense-instantsearch-adapter следующим образом:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "..." ,
nearestNode : { ... } ,
nodes : [ ... ] ,
useServerSideSearchCache : true // <<< Add this to send use_cache as a query parameter instead of post body parameter
} ,
additionalSearchParameters : { ... }
} ) ;
Это приведет к тому, что адаптер добавит ?use_cache=true
в качестве параметра URL-запроса ко всем поисковым запросам, инициированным адаптером, что затем заставит сервер Typesense включить кэширование на стороне сервера для этих запросов.
Кэширование на стороне клиента:
В адаптере также по умолчанию включено кэширование на стороне клиента, чтобы предотвратить ненужные сетевые вызовы на сервер. TTL для этого клиентского кэша можно настроить следующим образом:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "..." ,
nearestNode : { ... } ,
nodes : [ ... ] ,
cacheSearchResultsForSeconds : 2 * 60 // <<< Add this to configure the TTL for client-side cache in the browser
} ,
additionalSearchParameters : { ... }
} ) ;
Типсенс сервер | typeense-instantsearch-адаптер | Instantsearch.js | реакция-мгновенный поиск | vue-мгновенный поиск | угловой-мгновенный поиск |
---|---|---|---|---|---|
>= v0.25.0 | >= v2.7.1 | >= 4,51 | >= 6,39 | >= 4,8 | >= 4,4 |
>= v0.25.0.rc14 | >= v2.7.0-1 | >= 4,51 | >= 6,39 | >= 4,8 | >= 4,4 |
>= v0.25.0.rc12 | >= v2.6.0 | >= 4,51 | >= 6,39 | >= 4,8 | >= 4,4 |
>= v0.24 | >= v2.5.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.21 | >= v2.0.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.19 | >= v1.0.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.15 | >= v0.3.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.14 | >= v0.2.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.13 | >= v0.1.0 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
>= v0.12 | >= v0.0.4 | >= 4.2.0 | >= 6.0.0 | >= 2.2.1 | >= 3.0.0 |
Если определенная версия вышеуказанных библиотек не работает с адаптером, откройте проблему на Github с подробными сведениями.
Этот адаптер работает со всеми виджетами из этого списка.
$ npm install
$ npm run typesenseServer
$ FORCE_REINDEX=true npm run indexTestData
$ npm link typesense-instantsearch-adapter
$ npm run testground
$ npm test
Для выпуска новой версии мы используем пакет np:
$ npm install --global np
$ np
# Follow instructions that np shows you
Если у вас есть какие-либо вопросы или вы столкнулись с какими-либо проблемами, создайте проблему на Github, и мы постараемся помочь.
© Typesense, Inc., 2020 г. по настоящее время.