一个适配器,用于将很棒的 Instantsearch.js 库与 Typesense 搜索服务器结合使用,以构建丰富的搜索界面。
以下是您可以使用此适配器构建的 UI 示例:songs-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-components.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 以从入门模板创建您的搜索 UI。
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。
应用程序.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" } ,
] ,
} ) ,
] ) ;
value 属性的通用模式为: <index_name>[/sort/<sort_by>]
。适配器将使用<sort_by>
中的值作为sort_by
搜索参数的值。
configure
如果您需要为 Typesense 指定一个filter_by
搜索参数,您需要使用configure
InstantSearch 小部件以及facetFilters
、 numericFilters
或filters
。
facetFilters
和numericFilters
的格式与 Algolia 的格式相同,如此处所述。但filters
需要采用 Typesense 的filter_by
格式,如此表中所述。
仅在最初加载小部件时,在additionalQueryParameters
配置中设置filter_by
才有效,因为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 ;
本质上,在查询 Typesense 时, collectionSpecificSearchParameters
中设置的任何参数都将与additionalSearchParameters
中的值合并,从而有效地基于每个集合覆盖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
小部件开箱即用,无需额外更改,但如果您想控制这些方面在UI中显示的顺序,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 ,
} ) ;
请在此处阅读 Algolia 文档中有关renderingContent
的所有可用选项的更多信息。
自 typesense-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 ,
} ) ;
请注意,为了在refinementLists中进行排序,除了在Typesense服务器端进行排序之外,您还需要将sortBy
参数传递给refinementList小部件,以便在客户端对结果进行适当的排序。
filter_by
选项自 typesense-instantsearch-adapter
2.8.0-5
起可用
当您使用各种过滤器小部件时, filter_by
参数由 InstantSearch 在内部管理。
默认情况下,适配器在将查询发送到 Typesense 时使用精确过滤 ( filter_by: field:=value
)。如果需要将适配器配置为使用:
(非精确字级过滤 - 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 ,
} ) ;
自 typesense-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
。
从 typesense-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 ,
} ) ;
自 typesense-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 ( ) ;
}
} ,
} ) ;
缓存有两种模式:
服务器端缓存:
要启用服务器端缓存,请在 typesense-instantsearch-adapter 的server
配置块中添加一个名为useServerSideSearchCache: true
的参数,如下所示:
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 Server 为这些请求启用服务器端缓存。
客户端缓存:
该适配器还默认启用客户端缓存,以防止对服务器进行不必要的网络调用。客户端缓存的 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 : { ... }
} ) ;
类型感应服务器 | typesense-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 问题,我们将尽力提供帮助。
© 2020 年至今 Typesense, Inc.