Typesense est une excellente alternative open source pour AlgolieÉtant donné qu'Algolia propose un package tarifaire assez cher, il pourrait être intéressant de jeter un œil à Typesense.
En plus de cela, il dispose déjà de certaines intégrations avec des packages célèbres comme Recherche instantanée.js et Laravel Scout.
Cela a commencé récemment, donc sa documentation manque encore de quelques exemples. C'est pourquoi j'ai écrit ce post :
Utilisation de Typesense pour Laravel
Ce qui est génial, c'est qu'il existe un package Laravel Scout disponible : https://github.com/devloopsnet/laravel-scout-typesense-engine
Correction des premières erreurs Typesense avec Laravel :
Il est fort probable que vous receviez des erreurs lorsque vous utilisez les paramètres par défaut tels que décrits dans le package Typesense Laravel Scout :
{"message": "Le champ `id` du document doit être une chaîne."}
Cela peut être résolu en convertissant l'ID en une chaîne dans le tableau consultable :
/** * Obtenir le tableau de données indexable pour le modèle. * * @return array */ public function toSearchableArray() { $array = $this->toArray();// Spécifique à Typesense
si (config('scout.driver') == 'typesensesearch') {
$array['id'] = (chaîne)$array['id']; $array['created_at'] = (entier)\Carbon::parse($array['created_at'])->timestamp;
}
retourner $array;
}
Notez que j'ai également converti la valeur datetime created_at en un entier d'horodatage, afin que Typesense puisse facilement trier sur la valeur entière de la date.
Ajout de l'adaptateur Typesense Instantsearch.js à Laravel
Vous pouvez suivre les étapes décrites par le Instructions pour l'adaptateur Typesense. N'oubliez pas non plus d'installer npm algoliasearch et instantsearch.js .
Insertion dans Laravel Mix
Vous pouvez insérer le code suivant dans le fichier webpack.mix.js pour Laravel Mix :
mix.extract(['algoliasearch', 'instantsearch.js', 'typesense-instantsearch-adapter']) .js(['resources/js/app.js'], 'public/js');
Dans votre resources/js/app.js, préparez également les importations :
importer instantsearch depuis "instantsearch.js"; window.instantsearch = instantsearch; importer { searchBox, hits, index } depuis "instantsearch.js/es/widgets"; window.searchBox = searchBox; window.hits = hits; window.index = index; importer { connectAutocomplete } depuis 'instantsearch.js/es/connectors'; window.connectAutocomplete = connectAutocomplete; importer TypesenseInstantSearchAdapter depuis "typesense-instantsearch-adapter"; window.TypesenseInstantSearchAdapter = TypesenseInstantSearchAdapter;
Notez que j'ai également inclus index et connectAutocomplete qui sont requis pour le widget de saisie semi-automatique. Si vous ne prévoyez pas de les utiliser, vous pouvez les laisser de côté.
Exécutez Laravel Mix avec (utilisez également npm install si Mix n'a jamais été initialisé) :
npm exécuter dev
Dans votre fichier de mise en page principal, ajoutez les fichiers de mixage générés :
Ensuite, vous pouvez simplement insérer les résultats et le champ de recherche :
<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>
J'ai ajouté le thème CSS d'instantsearch.js pour lui donner un style de base. Celui-ci ne semble pas encore fonctionner pour la saisie semi-automatique. Vous devez entièrement styliser celui-ci vous-même (pour autant que je sache).
Comment utiliser la saisie semi-automatique d'Instantsearch.js avec Typesense
Typesense a écrit un adaptateur qui fonctionne avec Recherche instantanée.js pour Algolia. Il a quelques exemples de base pour utiliser les composants hits et searchBox.
Dans certains cas, vous souhaiterez étendre cette fonctionnalité. Par exemple, si vous souhaitez utiliser le Complétion automatique d'Instantsearch.js Pour cette fonctionnalité, vous devez écrire du code supplémentaire. Pour créer une fonctionnalité de saisie semi-automatique de base avec plusieurs indices, vous pouvez utiliser ce code :
Utilisation de plusieurs index et de la saisie semi-automatique pour Instantsearch.js
Dans cet exemple, j'ai copié le code du site Web de saisie semi-automatique Instantsearch.js d'Algolia et intégré l'adaptateur 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>
N'oubliez pas de renseigner les variables TYPESENSE_SEARCH_KEY et TYPESENSE_HOST dans vos variables d'environnement. Et remplacez le premier index products par l'index souhaité. Remplacez « landings » par le deuxième index souhaité. Vous pouvez ajouter d'autres index en ajoutant :
index({searchClient, indexName: 'un autreIndex' }),
à la partie search.AddWidgets.
N'oubliez pas que nous devons également importer le connecteur de saisie semi-automatique et le widget du composant d'index via Laravel Mix.