Búsqueda con Typesense para Laravel Scout

Usando Typesense como su proveedor de búsqueda para Laravel Scout e Instantsearch.

Typesense es una gran alternativa de código abierto para AlgoliaDado que Algolia tiene un paquete de precios bastante caro, podría valer la pena echarle un vistazo a Typesense.

Además de eso, ya tiene algunas integraciones con paquetes famosos como Búsqueda instantánea.js y Explorador de Laravel.

Comenzó hace poco, por lo que su documentación aún carece de algunos ejemplos. Por eso he escrito este post:

Uso de Typesense para Laravel

Lo bueno es que hay un paquete Laravel Scout disponible: https://github.com/devloopsnet/laravel-scout-typesense-engine

Arreglando los primeros errores de Typesense con Laravel:

Lo más probable es que recibas errores cuando uses la configuración predeterminada como se describe en el paquete Typesense Laravel Scout:

{"message": "El campo `id` del documento debe ser una cadena."}

Esto se puede solucionar convirtiendo el id en una cadena en la matriz de búsqueda:

/** * Obtener la matriz de datos indexables para el modelo. * * @return array */ public function toSearchableArray() { $array = $this->toArray();
   // Específico del sentido de tipos
   si (config('scout.driver') == 'typesensesearch') {
      $array['id'] = (cadena)$array['id']; $array['created_at'] = (entero)\Carbon::parse($array['created_at'])->timestamp;
   }
   devuelve $array;
}

Tenga en cuenta que también convertí el valor de fecha y hora created_at en un entero de marca de tiempo, para que Typesense pudiera ordenar fácilmente el valor entero de la fecha.

Cómo agregar el adaptador Typesense de Instantsearch.js a Laravel

Puede seguir los pasos tal y como se describe en el Instrucciones del adaptador TypesenseTampoco olvides instalar npm algoliasearch y instantsearch.js.

Inserción en Laravel Mix

Puede insertar el siguiente código en el archivo webpack.mix.js para Laravel Mix:

mix.extract(['algoliasearch', 'instantsearch.js', 'adaptador-typesense-instantsearch-adapter']) .js(['resources/js/app.js'], 'public/js');

En su archivo resources/js/app.js también prepare las importaciones:

importar instantsearch desde "instantsearch.js"; ventana.instantsearch = instantsearch; importar { searchBox, hits, index } desde "instantsearch.js/es/widgets"; ventana.searchBox = searchBox; ventana.hits = hits; ventana.index = index; importar { connectAutocomplete } desde 'instantsearch.js/es/connectors'; ventana.connectAutocomplete = connectAutocomplete; importar TypesenseInstantSearchAdapter desde "typesense-instantsearch-adapter"; ventana.TypesenseInstantSearchAdapter = TypesenseInstantSearchAdapter;

Tenga en cuenta que también he incluido index y connectAutocomplete, que son necesarios para el widget de autocompletar. Si no tiene pensado utilizarlos, puede omitirlos.

Ejecute Laravel Mix con (también use npm install si Mix nunca se ha inicializado):

npm ejecuta dev

En el archivo de diseño principal de la hoja, agregue los archivos de mezcla generados:

Luego puedes simplemente insertar los resultados y el cuadro de búsqueda:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/themes/reset-min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/themes/algolia-min.css">


<div id="hits"></div>
<div id="searchbox"></div>

<script>
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
  server: {
    apiKey: "{{ env('TYPESENSE_SEARCH_KEY') }}", // Be sure to use the search-only-api-key
    nodes: [
      {
        host: "{{ env('TYPESENSE_HOST') }}",
        port: "443",
        protocol: "https"
      }
    ]
  },
  // The following parameters are directly passed to Typesense's search API endpoint.
  //  So you can pass any parameters supported by the search endpoint below. 
  //  queryBy is required. 
  additionalSearchParameters: {
    queryBy: "name"
  }
});
const searchClient = typesenseInstantsearchAdapter.searchClient;

const search = instantsearch({
  searchClient,
  indexName: "products"
});

// Create the custom widget
const customAutocomplete = connectAutocomplete(
  renderAutocomplete
);

// Instantiate the custom widget
search.addWidgets([
  index({ searchClient, indexName: 'autolandings' }),

  customAutocomplete({
    container: document.querySelector('#autocomplete'),
  })
]);

search.start();
</script>

He añadido el tema CSS de instantsearch.js para darle un estilo básico. Este no parece funcionar todavía con el autocompletado. Tienes que diseñarlo tú mismo (hasta donde yo sé).

Cómo utilizar el autocompletado de Instantsearch.js con Typesense

Typesense escribió un adaptador que funciona con Búsqueda instantánea.js para Algolia. Tiene algunos ejemplos básicos para utilizar el componente hits y searchBox.

En algunos casos, es posible que desee ampliar esta funcionalidad. Por ejemplo, si desea utilizar el Autocompletar en Instantsearch.js Para crear una funcionalidad de autocompletado básica con varios índices, se debe escribir código adicional.

Uso de múltiples índices y autocompletado para Instantsearch.js

En este ejemplo, he copiado el código del sitio web de autocompletado Instantsearch.js de Algolia e integré el adaptador Typesense:

<div id="autocomplete"></div>

<script>
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
  server: {
    apiKey: "{{ env('TYPESENSE_SEARCH_KEY') }}", // Be sure to use the search-only-api-key
    nodes: [
      {
        host: "{{ env('TYPESENSE_HOST') }}",
        port: "443",
        protocol: "https"
      }
    ]
  },
  // The following parameters are directly passed to Typesense's search API endpoint.
  //  So you can pass any parameters supported by the search endpoint below. 
  //  queryBy is required. 
  additionalSearchParameters: {
    queryBy: "name"
  }
});
const searchClient = typesenseInstantsearchAdapter.searchClient;

const search = instantsearch({
  searchClient,
  indexName: "products"
});

// Helper for the render function
const renderIndexListItem = ({ indexId, hits }) => `
  <li>
    Index: ${indexId}
    <ol>
      ${hits
        .map(
          (hit, hitIndex) =>
            `
              <li>
                <p>${instantsearch.highlight({ attribute: 'name', hit })}</p>
                <button
                  type="button"
                  class="btn-add-to-cart"
                  data-index-id="${indexId}"
                  data-hit-index="${hitIndex}"
                >
                  Add to Cart
                </button>
              </li>
            `
        )
        .join('')}
    </ol>
  </li>
`;

// Create the render function
const renderAutocomplete = (renderOptions, isFirstRender) => {
  const { indices, currentRefinement, refine, widgetParams } = renderOptions;

  if (isFirstRender) {
    const input = document.createElement('input');
    const ul = document.createElement('ul');

    input.addEventListener('input', event => {
      refine(event.currentTarget.value);
    });

    widgetParams.container.appendChild(input);
    widgetParams.container.appendChild(ul);

    ul.addEventListener('click', (event) => {
      if (event.target.className === 'btn-add-to-cart') {
        const indexId = event.target.getAttribute('data-index-id');
        const hitIndex = event.target.getAttribute('data-hit-index');
        const index = indices.find(index => index.indexId === indexId);
        const hit = index.hits[hitIndex];

        index.sendEvent('conversion', hit, 'Product Added');
      }
    });
  }

  widgetParams.container.querySelector('input').value = currentRefinement;
  widgetParams.container.querySelector('ul').innerHTML = indices
    .map(renderIndexListItem)
    .join('');
};

// Create the custom widget
const customAutocomplete = connectAutocomplete(
  renderAutocomplete
);

// Instantiate the custom widget
search.addWidgets([
  index({ searchClient, indexName: 'landings' }),

  customAutocomplete({
    container: document.querySelector('#autocomplete'),
  })
]);

search.start();
</script>

No olvides completar TYPESENSE_SEARCH_KEY y TYPESENSE_HOST en tus variables de entorno. Y reemplaza el primer índice products con el índice que desees. Reemplaza 'landings' con el segundo índice que desees. Puedes agregar más índices agregando:

índice({searchClient, indexName: 'otroÍndice' }),

a la parte de búsqueda.AddWidgets.

Tenga en cuenta que también debemos importar el conector de autocompletar y el widget del componente de índice a través de Laravel Mix.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

es_ESEspañol
Ir arriba