Un adaptador para utilizar la increíble biblioteca Instantsearch.js con un servidor de búsqueda Typesense para crear interfaces de búsqueda enriquecidas.
Aquí hay un ejemplo de interfaz de usuario que puede crear con este adaptador: canciones-search.typesense.org
Nota: Si su interfaz de búsqueda está construida sobre un componente de autocompletar personalizado, o está basada en @algolia/autocomplete-js, entonces no necesita este adaptador para usarlo con Typesense, ya que la biblioteca Typesense-js ya admite la búsqueda del lado del cliente. datos de cualquier fuente de datos asincrónicos. Lea más aquí.
La buena gente de Algolia ha creado Instantsearch.js de código abierto, que es una colección de componentes listos para usar que puede utilizar para crear experiencias de búsqueda interactivas rápidamente.
Con el adaptador de este repositorio, podrá utilizar Instantsearch (y sus primos React, Vue y Angular) con datos indexados en un servidor de búsqueda Typesense.
Si no ha utilizado Instantsearch antes, le recomendamos consultar su guía de introducción aquí. Una vez que haya leído la guía, siga las instrucciones a continuación para conectar el adaptador Typesense a Instantsearch.
Aquí hay una guía sobre cómo crear una interfaz de búsqueda rápida con Typesense e InstantSearch.js: https://typesense.org/docs/0.20.0/guide/search-ui-components.html
Aquí hay una aplicación inicial de demostración que le muestra cómo usar el adaptador: https://github.com/typesense/typesense-instantsearch-demo
$ npm install --save typesense-instantsearch-adapter @babel/runtime
o
$ yarn add typesense-instantsearch-adapter @babel/runtime
o también puedes incluir directamente el adaptador a través de una etiqueta de script en tu 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 -->
Dado que se trata de un adaptador, no instalará la biblioteca Instantsearch automáticamente. Debe instalar uno de los siguientes en su aplicación directamente:
Encontrará información sobre cómo comenzar con cada una de las bibliotecas anteriores en sus respectivos repositorios.
También recomendamos consultar create-instantsearch-app para crear su interfaz de usuario de búsqueda a partir de una plantilla inicial.
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 ( ) ;
Puede agregar aquí cualquiera de los widgets de Instantsearch que sean compatibles con el adaptador.
También encontrará un ejemplo funcional en test/support/testground. Para ejecutarlo, ejecute npm run testground
desde la carpeta raíz del proyecto.
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 >
) ;
Luego puede agregar aquí cualquiera de los widgets Instantsearch-React que sean compatibles con el adaptador.
Las instrucciones anteriores también se aplican a React Native.
Aplicación.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 >
Luego puede agregar aquí cualquiera de los widgets de Instantsearch que sean compatibles con el adaptador.
// 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 ,
} ;
}
Luego puede agregar aquí cualquiera de los widgets de Instantsearch que sean compatibles con el adaptador.
hierarchicalMenu
Para este widget, desea crear campos independientes en el esquema de la colección con esta convención de nomenclatura específica:
field.lvl0
field.lvl1
field.lvl2
para una jerarquía anidada de field.lvl0 > field.lvl1 > field.lvl2
Cada uno de estos campos también puede contener una serie de valores. Esto es útil para manejar múltiples jerarquías.
sortBy
Al crear una instancia de este widget, desea establecer el valor del nombre del índice en este formato particular:
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" } ,
] ,
} ) ,
] ) ;
El patrón generalizado para el atributo de valor es: <index_name>[/sort/<sort_by>]
. El adaptador utilizará el valor en <sort_by>
como valor para el parámetro de búsqueda sort_by
.
configure
Si necesita especificar un parámetro de búsqueda filter_by
para Typesense, desea utilizar el widget configure
InstantSearch, junto con facetFilters
, numericFilters
o filters
.
El formato para facetFilters
y numericFilters
es el mismo que el de Algolia, como se describe aquí. Pero filters
deben estar en el formato filter_by
de Typesense como se describe en esta tabla aquí.
Configurar filter_by
dentro de la configuración additionalQueryParameters
solo funciona cuando los widgets se cargan inicialmente, porque InstantSearch anula internamente el campo filter_by
posteriormente. Lea más aquí.
index
Para la búsqueda federada/multiíndice, deberá utilizar el widget index
. Para luego poder especificar diferentes parámetros de búsqueda para cada índice/colección, puede especificarlos usando la configuración 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 ;
Esencialmente, cualquier parámetro establecido en collectionSpecificSearchParameters
se fusionará con los valores en additionalSearchParameters
al consultar Typesense, anulando efectivamente los valores en additionalSearchParameters
por colección.
geoSearch
Algolia usa _geoloc
de forma predeterminada para el nombre del campo que almacena los valores de latitud y longitud de un registro. En Typesense, puedes nombrar el campo de ubicación geográfica como quieras. Si usa un nombre distinto de _geoloc
, debe especificarlo al inicializar el adaptador como se muestra a continuación, para que InstantSearch pueda acceder a él:
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
geoLocationField : "lat_lng_field" , // <<======
additionalSearchParameters ,
} ) ;
dynamicWidgets
Disponible a partir de Typesense Server
v0.25.0.rc12
Este widget de dynamicWidgets
funciona de inmediato sin cambios adicionales, pero si desea controlar el orden en el que se muestran estas facetas en la interfaz de usuario, Instantsearch espera que se establezca un parámetro llamado 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 ,
} ) ;
Lea más sobre todas las opciones disponibles para renderingContent
en la documentación de Algolia aquí.
Disponible a partir de typesense-instantsearch-adapter
2.7.0-2
Si algún campo de cadena en sus documentos tiene dos puntos :
en sus valores (por ejemplo, digamos que hay un campo llamado { brand: "a:b" }
, entonces deberá agregar un parámetro como el siguiente al crear una instancia del adaptador:
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 ,
} ) ;
Si algún nombre de campo numérico en sus documentos tiene caracteres especiales como >
, <
, =
(por ejemplo, digamos que hay un campo llamado { price>discount: 3.0 }
), entonces deberá agregar un parámetro como el siguiente al crear una instancia del adaptador:
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
Disponible a partir de Typesense-instantsearch-adapter
2.8.0-1
y Typesense Serverv0.26.0.rc25
InstantSearch administra internamente el parámetro facet_by
cuando se utilizan los distintos widgets de filtro.
Pero si necesita pasar opciones personalizadas al parámetro facet_by
(por ejemplo, opciones de clasificación del lado del servidor), puede usar el parámetro facetByOptions
como se muestra a continuación:
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 ,
} ) ;
Tenga en cuenta que para ordenar en refinementLists, además de ordenar en el lado del servidor Typesense, también necesitará pasar el parámetro sortBy
al widget refinementList para ordenar también los resultados adecuadamente en el lado del cliente.
filter_by
Disponible a partir de typesense-instantsearch-adapter
2.8.0-5
InstantSearch administra internamente el parámetro filter_by
cuando se utilizan los distintos widgets de filtro.
De forma predeterminada, el adaptador utiliza filtrado exacto ( filter_by: field:=value
) al enviar las consultas a Typesense. Si necesita configurar el adaptador para usar :
(filtrado a nivel de palabra no exacto - filter_by: field:value
), desea crear una instancia del adaptador usando la configuración 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 ,
} ) ;
Disponible a partir de typesense-instantsearch-adapter
2.9.0-0
A continuación se muestra una manera de deshabilitar las anulaciones/reglas de curación cuando los usuarios seleccionan un orden de clasificación en particular:
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 ,
} ) ;
Si tiene widgets sortBy configurados con un valor indexName de products/sort/price:asc
, por ejemplo, entonces la clave dentro de sortByOptions
debe ser price:asc
.
Disponible a partir de typesense-instantsearch-adapter
2.7.1-4
De forma predeterminada, cuando se utiliza group_by
como parámetro de búsqueda, el adaptador aplana los resultados de todos los grupos en una única lista de resultados secuenciales.
Si desea conservar los grupos, debe configurar flattenGroupedHits: false
al crear una instancia del adaptador.
Esto colocará el primer hit de un grupo como el hit principal y luego agregará todos los hits del grupo dentro de una clave _grouped_hits
dentro de cada hit.
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter ( {
server : {
apiKey : "xyz" ,
nodes : [
{
host : "localhost" ,
port : "8108" ,
path : "/" ,
protocol : "http" ,
} ,
] ,
} ,
flattenGroupedHits : false , // <=======
additionalSearchParameters ,
} ) ;
Disponible a partir de typesense-instantsearch-adapter
2.7.0-3
La idea general es conectarse primero al ciclo de vida de la consulta de Instantsearch, interceptar la consulta escrita y enviarla a una API de incrustación, recuperar las incrustaciones y luego enviar los vectores a Typesense para realizar una búsqueda de vectores vecinos más cercanos.
Aquí hay una demostración que puede ejecutar localmente para verlo en acción: https://github.com/typesense/showcase-hn-comments-semantic-search.
Aquí se explica cómo hacer esto en 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 ( ) ;
}
} ,
} ) ;
Hay dos modos de almacenamiento en caché:
Almacenamiento en caché del lado del servidor:
Para habilitar el almacenamiento en caché del lado del servidor, agregue un parámetro llamado useServerSideSearchCache: true
en el bloque de configuración server
de Typesense-instantsearch-adapter como este:
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 : { ... }
} ) ;
Esto hará que el adaptador agregue ?use_cache=true
como parámetro de consulta de URL a todas las solicitudes de búsqueda iniciadas por el adaptador, lo que luego hará que Typesense Server habilite el almacenamiento en caché del lado del servidor para estas solicitudes.
Almacenamiento en caché del lado del cliente:
El adaptador también tiene habilitado el almacenamiento en caché del lado del cliente de forma predeterminada, para evitar llamadas de red innecesarias al servidor. El TTL para esta caché del lado del cliente se puede configurar así:
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 : { ... }
} ) ;
Servidor Typesense | adaptador-de-búsqueda-instantánea-typesense | búsqueda instantánea.js | reaccionar-búsqueda instantánea | vue-búsqueda instantánea | búsqueda instantánea angular |
---|---|---|---|---|---|
>=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 |
Si una versión particular de las bibliotecas anteriores no funciona con el adaptador, abra un problema de Github con detalles.
Este adaptador funciona con todos los widgets de esta lista
$ npm install
$ npm run typesenseServer
$ FORCE_REINDEX=true npm run indexTestData
$ npm link typesense-instantsearch-adapter
$ npm run testground
$ npm test
Para lanzar una nueva versión, usamos el paquete np:
$ npm install --global np
$ np
# Follow instructions that np shows you
Si tiene alguna pregunta o tiene algún problema, cree un problema en Github y haremos todo lo posible para ayudarlo.
© 2020-presente Typesense, Inc.