<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meilisearch</title>
    <description>The latest articles on DEV Community by Meilisearch (@meilisearch).</description>
    <link>https://dev.to/meilisearch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3048%2F4c6c49a0-7adb-4a28-8920-01f2766b65b7.png</url>
      <title>DEV Community: Meilisearch</title>
      <link>https://dev.to/meilisearch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meilisearch"/>
    <language>en</language>
    <item>
      <title>Vector storage is coming to Meilisearch to empower search through AI</title>
      <dc:creator>Strift</dc:creator>
      <pubDate>Tue, 11 Jul 2023 11:05:36 +0000</pubDate>
      <link>https://dev.to/meilisearch/vector-storage-is-coming-to-meilisearch-to-empower-search-through-ai-3i1f</link>
      <guid>https://dev.to/meilisearch/vector-storage-is-coming-to-meilisearch-to-empower-search-through-ai-3i1f</guid>
      <description>&lt;p&gt;Vector search enables efficient retrieval of objects sharing similar characteristics. This AI-powered search technique uses embedding vectors. These vectors are mathematical representations of objects generated by machine learning models (like LLMs). In the upcoming 1.3 release, Meilisearch will support storing and searching vectors.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The release candidate for Meilisearch v1.3 is out—&lt;a href="https://github.com/meilisearch/meilisearch/releases/tag/v1.3.0-rc.0"&gt;try it now&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Powering the Future of Search
&lt;/h2&gt;

&lt;p&gt;Vector search might be the dawn of a new era for search. Its use cases are numerous. In &lt;a href="https://ecommerce.meilisearch.com/?utm_campaign=vector-search&amp;amp;utm_source=devto"&gt;ecommerce&lt;/a&gt;, it enables offering recommendations for similar products. It also allows building multi-modal search, like image or audio search. Building upon conversational AI technologies enables the creation of Q&amp;amp;A applications. Combining vector search with user-provided information like geolocation and search history can power even more contextual search experiences. &lt;/p&gt;

&lt;p&gt;Vector search is also the foundation for &lt;a href="https://en.wikipedia.org/wiki/Semantic_search"&gt;semantic search&lt;/a&gt;, which aims to understand the query’s meaning. Conversely, traditional lexical search only matches keywords. With semantic search, a &lt;code&gt;warm clothes&lt;/code&gt; query could give results like &lt;code&gt;gloves&lt;/code&gt;, &lt;code&gt;coat&lt;/code&gt;, and more results related to winter clothing.&lt;/p&gt;

&lt;p&gt;Vector search unlocks a world of new capabilities for search. Take a look at what some users have already implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/adrienpoly/rubyvideo/pull/19"&gt;similar videos recommendations&lt;/a&gt; on a site listing Ruby conferences&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://blazy-chat.vercel.app/"&gt;documentation chatbot&lt;/a&gt; proof of concept using &lt;a href="https://platform.openai.com/docs/models/gpt-3-5"&gt;GPT3.5&lt;/a&gt; and &lt;a href="https://github.com/hwchase17/langchain"&gt;LangChain&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started with Meilisearch vector store
&lt;/h2&gt;

&lt;p&gt;Starting with v1.3, you can use Meilisearch as a vector store. Meilisearch allows you to store vector embeddings alongside your documents conveniently. You will need to create the vector embeddings using your third-party tool of choice (&lt;a href="https://huggingface.co/"&gt;Hugging Face&lt;/a&gt;, &lt;a href="https://openai.com/"&gt;OpenAI&lt;/a&gt;). As we published the first &lt;a href="https://github.com/meilisearch/meilisearch/releases/tag/v1.3.0-rc.0"&gt;v1.3 release candidate&lt;/a&gt;, you can try out vector search today.&lt;/p&gt;

&lt;p&gt;First, pull the release candidate by using this Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 7700:7700 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/meili_data:/meili_data getmeili/meilisearch:v1.3.0-rc.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, enable the vector store experimental feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; PATCH &lt;span class="s1"&gt;'http://localhost:7700/experimental-features/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt;  &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s1"&gt;'{
    "vectorStore": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 This guide uses curl to make HTTP requests to communicate with Meilisearch. When v1.3 will officially be released, you will be able to use the corresponding &lt;a href="https://github.com/meilisearch/integration-guides"&gt;SDK methods&lt;/a&gt; instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meilisearch now accepts a &lt;code&gt;_vector&lt;/code&gt; field in your documents. Use it to store the vector embeddings corresponding to your document in this field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="s1"&gt;'localhost:7700/indexes/songs/documents'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s1"&gt;'[
         { "id": 0, "_vectors": [0, 0.8, -0.2], "title": "Across The Universe" },
         { "id": 1, "_vectors": [1, -0.2, 0], "title": "All Things Must Pass" },
         { "id": 2, "_vectors": [[0.5, 3, 1], [-0.2, 4, 6]], "title": "And Your Bird Can Sing" }
     ]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After storing your vectorized documents in Meilisearch, you can query them using the &lt;code&gt;search&lt;/code&gt; or &lt;code&gt;multi-search&lt;/code&gt; route. To do this, you need to compute the vector of your query (using a third-party tool) and send it in the &lt;code&gt;vector&lt;/code&gt; field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="s1"&gt;'localhost:7700/indexes/songs/search'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s1"&gt;'{ "vector": [0, 1, 2] }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using vector search, returned documents include a &lt;code&gt;semanticScore&lt;/code&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"hits"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt;: 0, &lt;span class="s2"&gt;"_vectors"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;0, 0.8, &lt;span class="nt"&gt;-0&lt;/span&gt;.2], &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"Across The Universe"&lt;/span&gt;, &lt;span class="s2"&gt;"_semanticScore"&lt;/span&gt;: 0.6754 &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt;: 1, &lt;span class="s2"&gt;"_vectors"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;1, &lt;span class="nt"&gt;-0&lt;/span&gt;.2, 0], &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"All Things Must Pass"&lt;/span&gt;, &lt;span class="s2"&gt;"_semanticScore"&lt;/span&gt;: 0.7546 &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt;: 2, &lt;span class="s2"&gt;"_vectors"&lt;/span&gt;: &lt;span class="o"&gt;[[&lt;/span&gt;0.5, 3, 1], &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-0&lt;/span&gt;.2, 4, 6]], &lt;span class="s2"&gt;"title"&lt;/span&gt;: &lt;span class="s2"&gt;"And Your Bird Can Sing"&lt;/span&gt;, &lt;span class="s2"&gt;"_semanticScore"&lt;/span&gt;: 0.78 &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;,
  &lt;span class="s2"&gt;"query"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
  &lt;span class="s2"&gt;"vector"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;0, 1, 2],
  &lt;span class="s2"&gt;"processingTimeMs"&lt;/span&gt;: 0,
  &lt;span class="s2"&gt;"limit"&lt;/span&gt;: 20,
  &lt;span class="s2"&gt;"offset"&lt;/span&gt;: 0,
  &lt;span class="s2"&gt;"estimatedTotalHits"&lt;/span&gt;: 2
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📢 This API is experimental. You can help us improve it by sharing your feedback in &lt;a href="https://github.com/meilisearch/product/discussions/677"&gt;this Github discussion&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A First Step Toward Semantic Search
&lt;/h2&gt;

&lt;p&gt;Vector search is our first step towards semantic search. But our long-term goal is to provide hybrid search—combining the benefits of full-text and semantic search to provide the most relevant search experience. Clément Renault, founder and CTO of Meilisearch, shared his thoughts on Github about &lt;a href="https://github.com/meilisearch/meilisearch/issues/3838"&gt;exploring semantic search&lt;/a&gt; — read for a founder’s perspective. We can’t wait to share more with you!&lt;/p&gt;

&lt;p&gt;Drop your email below to learn more about our progress with AI-powered search. We’ll keep you posted on all updates regarding vector search &amp;amp; semantic search.&lt;/p&gt;

&lt;p&gt;We’re excited to walk our first steps toward semantic search. We can’t wait to hear your thoughts on integrating Meilisearch as a vector store. You can give your feedback in &lt;a href="https://github.com/meilisearch/product/discussions/677"&gt;this Github discussion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can stay in the loop by subscribing to our &lt;a href="https://meilisearch.us2.list-manage.com/subscribe?u=27870f7b71c908a8b359599fb&amp;amp;id=79582d828e"&gt;newsletter&lt;/a&gt;. To learn more about Meilisearch's future and help shape it, look at our &lt;a href="https://roadmap.meilisearch.com/"&gt;roadmap&lt;/a&gt; and participate in our &lt;a href="https://github.com/meilisearch/product/discussions/"&gt;Product Discussions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For anything else, join our developers community on &lt;a href="https://discord.gg/meilisearch"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ll see you there.&lt;/p&gt;

</description>
      <category>search</category>
      <category>machinelearning</category>
      <category>database</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to deliver the best search results: inside a full text search engine</title>
      <dc:creator>Carolina</dc:creator>
      <pubDate>Tue, 04 Jul 2023 10:30:00 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-deliver-the-best-search-results-inside-a-full-text-search-engine-1e17</link>
      <guid>https://dev.to/meilisearch/how-to-deliver-the-best-search-results-inside-a-full-text-search-engine-1e17</guid>
      <description>&lt;p&gt;Search bars are an integral part of browsing the web. Whether we are shopping for clothes, enjoying music, or planning a vacation, there is always a dedicated search engine at work to simplify our lives. Have you ever wondered how these search engines actually work? In this article, we will delve into the inner workings of one of them: Meilisearch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexing time: from data to documents
&lt;/h2&gt;

&lt;p&gt;Indexing is a fundamental process that encompasses the collection, parsing, and storage of data for subsequent retrieval. It plays a crucial role in enabling search engines to deliver fast and relevant results.&lt;/p&gt;

&lt;h3&gt;
  
  
  A performant storage engine
&lt;/h3&gt;

&lt;p&gt;Meilisearch stores data in the form of discrete records called "&lt;a href="https://docs.meilisearch.com/learn/core_concepts/documents.html%20embed%20%20"&gt;documents&lt;/a&gt;," which are grouped together into collections known as "&lt;a href="https://docs.meilisearch.com/learn/core_concepts/indexes.html"&gt;indexes&lt;/a&gt;." Under the hood, Meilisearch uses the LMDB (&lt;a href="http://www.lmdb.tech/doc/?ref=blog.meilisearch.com"&gt;Lightning Memory-Mapped Database&lt;/a&gt;) key-value store which has proven stability and extensive usage in database applications. As the name implies, key-value stores are storage systems that organize data as a &lt;strong&gt;collection of key-value pairs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--153UFnsH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/focua1xcl7ymx017h90m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--153UFnsH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/focua1xcl7ymx017h90m.png" alt="Illustration of a key-value store with 'engine' set to 'meilisearch' and 'language' set to 'rust'" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Example of key-value entries



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Key-value stores offer flexibility, fast access times, and efficient performance, contributing to quick and responsive interactions for users. By permitting only a single writing process at a time, LMDB avoids synchronization-related issues. As a result, it enables unlimited concurrent readers to have fast access to up-to-date, consistent data.&lt;/p&gt;

&lt;p&gt;Before storing data in its key-value store, Meilisearch must preprocess it thoroughly. That’s where tokenization comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  From words to tokens
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Tokenization&lt;/strong&gt; involves two main processes: segmentation and normalization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Segmentation&lt;/strong&gt; consists in splitting a sentence or phrase into smaller units called tokens.&lt;/p&gt;

&lt;p&gt;Meilisearch uses (and maintains) the open-source tokenizer named &lt;a href="https://github.com/meilisearch/charabia"&gt;Charabia&lt;/a&gt;. The tokenizer is responsible for retrieving all the words (or tokens) from document fields.&lt;/p&gt;

&lt;p&gt;👉 In practice, Meilisearch users can configure which fields should be &lt;a href="https://www.meilisearch.com/docs/learn/configuration/displayed_searchable_attributes#searchable-fields"&gt;searchable&lt;/a&gt;, allowing Charabia to know which fields should be tokenized.&lt;/p&gt;

&lt;p&gt;Then comes normalization. Words are normalized based on each language’s particularities. For a romance language like French, this process includes setting the word in lowercase letters and removing diacritical marks such as accents. For instance, a sentence like “Le café de Nicolas” is transformed into “le cafe de nicolas”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ltKGxPYF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvp1cf8wrn0z8fxsnhnk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ltKGxPYF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uvp1cf8wrn0z8fxsnhnk.png" alt="The sentence 'Le café de Nicolas,' with a capital 'L' and 'N,' and an accent on the 'é' of 'café,' is first split into words during the segmentation phase. Then, during normalization, each word is lowercased, and accents are removed." width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;
Example of the segmentation and normalization stages in the tokenization process



&lt;p&gt;&lt;br&gt;&lt;br&gt;
After segmenting and normalizing words, the engine needs to classify them. Using the appropriate data structure to organize tokens is crucial for performance. This will later allow swift retrieval of the most relevant search results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing tokens
&lt;/h3&gt;

&lt;p&gt;Modern full-text search engines like Meilisearch come with features such as prefix search, typo tolerance, and geo search. Each data structure has its own advantages and disadvantages. When designing the search engine, our team carefully selected the ones best suited to enable these features without compromising on speed.&lt;/p&gt;

&lt;p&gt;Throughout this section, we will explore which data structures powers Meilisearch.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inverted index
&lt;/h4&gt;

&lt;p&gt;First and foremost, we need to talk about inverted indexes. Without a doubt, it’s the data structure that stands out by its importance. Meilisearch uses it to return documents fast upon search.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;inverted index&lt;/strong&gt; maps each word in a document to the set of documents where that term appears along with additional information like their position in the document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1X8p7_vP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55cirl1hus5e8j0mjsn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1X8p7_vP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/55cirl1hus5e8j0mjsn3.png" alt='Given the following documents: { “id”: 1 "title": "Hello world!" }, { “id”: 2 "title": "Hello Alice!" }. The inverted index would look like this: "alice" -&amp;gt; [2], "hello" -&amp;gt; [1,2], "world" -&amp;gt; [1]' width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
 Illustration of an inverted index generated from given documents, showcasing the mapping of keywords to document IDs 



&lt;p&gt;&lt;br&gt;&lt;br&gt;
By storing words once and associating them with the documents where they appear, inverted indexes leverage the redundancy of terms across documents. Thanks to this, Meilisearch does not need to browse all documents in order to find a given word, resulting in faster searches.&lt;/p&gt;

&lt;p&gt;Meilisearch creates approximately 20 inverted indexes per document index, making it one of the data structures with the highest number of instances. Indeed, to provide a search-as-you-type experience, the engine needs to precompute a lot at indexing time: word prefixes, documents containing filterable attributes, and more. For a better understanding of how inverted indexes work read more on &lt;a href="https://blog.meilisearch.com/best-practices-for-faster-indexing/"&gt;indexing best practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;💡 You can find the complete list of Meilisearch inverted indexes on &lt;a href="https://github.com/meilisearch/meilisearch/blob/78e611f282d726a604cfbc231666265a37c4d46b/milli/src/index.rs#L103-L157"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Roaring bitmap
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Roaring bitmaps&lt;/strong&gt; are compressed data structures designed for efficiently representing and manipulating sets of integers.&lt;/p&gt;

&lt;p&gt;Meilisearch uses roaring bitmaps widely throughout its inverted indexes to represent document IDs. Roaring bitmaps offer a space-efficient way to store large sets of integers and perform set operations like &lt;a href="https://en.wikipedia.org/wiki/De_Morgan%27s_laws"&gt;union, intersection, and difference&lt;/a&gt;. These operations play a crucial role in refining search results by allowing the inclusion or exclusion of specific documents based on their relationship with others.&lt;/p&gt;

&lt;h4&gt;
  
  
  Finite-state transducer
&lt;/h4&gt;

&lt;p&gt;A &lt;strong&gt;finite-state transducer&lt;/strong&gt; (FST) is a structured data representation ideal for performing string-matching operations. It represents a sequence of states ordered from smallest to largest, with words arranged in lexicographic order.&lt;/p&gt;

&lt;p&gt;ℹ️ &lt;a href="https://en.wikipedia.org/wiki/Lexicographic_order"&gt;Lexicographic order&lt;/a&gt; is a method of arranging or sorting items, such as words or symbols, based on their alphabetical or numerical sequence.&lt;/p&gt;

&lt;p&gt;A finite-state transducer is also called a word dictionary because it contains all words present in an index. Meilisearch relies on the utilization of two FSTs: one for storing all words of the dataset, and one for storing the most recurrent prefixes.&lt;/p&gt;

&lt;p&gt;FSTs are useful because they support compression and lazy decompression techniques, optimizing memory usage and storage. Additionally, by using automata such as regular expressions, they can retrieve subsets of words that match specific rules or patterns. Moreover, this enables the retrieval of all words that begin with a specific prefix, empowering fast, comprehensive search capabilities.&lt;/p&gt;

&lt;p&gt;The FST, with its compact design, presents the added advantage of being a smaller data structure than the inverted index. As we will see later, this contributes to faster and more efficient reading operations. You can learn more about the topic in this &lt;a href="https://blog.burntsushi.net/transducers/"&gt;comprehensive article on finite-state reducers&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  R-tree
&lt;/h4&gt;

&lt;p&gt;R-trees are a type of &lt;a href="https://en.wikipedia.org/wiki/Tree_(data_structure)"&gt;tree&lt;/a&gt; used for indexing multi-dimensional or spatial information. Meilisearch leverages R-trees to power its geo search functionality.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;R-tree&lt;/strong&gt; associates geographical coordinates with the identifiers of the document to which it belongs. By organizing coordinates this way, it enables Meilisearch to perform spatial queries with remarkable efficiency. These queries allow users to find nearby points, points within a specific area, or points that intersect with other spatial objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search time: query processing
&lt;/h2&gt;

&lt;p&gt;Modern search experiences only require you to start typing to get results. To achieve this search-as-you-type experience, Meilisearch precomputes a list of the most frequent prefixes.&lt;/p&gt;

&lt;p&gt;To be tolerant to typos, Meilisearch uses finite-state transducers in conjunction with the &lt;a href="https://www.meilisearch.com/docs/learn/configuration/typo_tolerance#understanding-typo-calculations"&gt;Levenshtein algorithm&lt;/a&gt;. This algorithm calculates the Levenshtein distance which can be thought of as the cost of transforming a string into another. In other words, it quantifies the number of transformations required for a word to be converted into another word.&lt;/p&gt;

&lt;p&gt;In the context of the Levenshtein algorithm, possible transformations are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  insertions, e.g. hat -&amp;gt; chat&lt;/li&gt;
&lt;li&gt;  deletions, e.g. tiger -&amp;gt; tier&lt;/li&gt;
&lt;li&gt;  substitutions, e.g. cat -&amp;gt; hat&lt;/li&gt;
&lt;li&gt;  transpositions or swaps, e.g. scared -&amp;gt; sacred&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FSTs generate all possible variations of a word within a specified edit distance, enabling the engine to calculate the Levenshtein distance and accurately detect typos by comparing user input against a dictionary of valid words.&lt;/p&gt;

&lt;p&gt;It becomes apparent that there are many factors to consider when processing a search request. Has the user finished typing? Are there typos in the query? Which documents should appear first in the search results?&lt;/p&gt;

&lt;p&gt;Let’s discuss how Meilisearch processes search queries and how it refines and sorts search results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query graph
&lt;/h3&gt;

&lt;p&gt;Each time it receives a search query, Meilisearch creates a query graph representing the query and its possible variations.&lt;/p&gt;

&lt;p&gt;To compute these variations, Meilisearch applies &lt;a href="https://www.meilisearch.com/docs/learn/advanced/concat#concatenated-queries"&gt;concatenation&lt;/a&gt; and &lt;a href="https://www.meilisearch.com/docs/learn/advanced/concat#split-queries"&gt;splitting&lt;/a&gt; algorithms to the query terms. The variations considered also include potential typos and synonyms–if the user set them. As an example, let’s examine the query: &lt;code&gt;the sun flower&lt;/code&gt;. Meilisearch will also search for the following queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;the sunflower&lt;/code&gt;: concatenation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;the sun flowed&lt;/code&gt;: substitution&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;the sun flowers&lt;/code&gt;: addition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider now a more complex query: &lt;code&gt;the sun flower is facing the su&lt;/code&gt;, the query graph should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D7qp7Xq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9y95romn745ruga6a1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D7qp7Xq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9y95romn745ruga6a1z.png" alt="Graph representing interpretations of the search query 'the sun flower is facing the su'. The engine precomputes for each query term word variations, like 'flowed' or 'flowers' and the associated Levenshtein cost" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;
Visual generated using our internal debugging tool, powered by &lt;a href="https://github.com/terrastruct/d2"&gt;D2&lt;/a&gt;, showcasing the execution process of search requests



&lt;p&gt;&lt;br&gt;&lt;br&gt;
As illustrated above, the graph represents different interpretations of the search query. The engine precomputes the word variations (and their cost) for each query term. Moreover, it detects whether the last query term is a prefix (not followed by a space), thus signaling the need to consult the prefix database.&lt;/p&gt;

&lt;p&gt;So how does the engine utilize a query graph?&lt;/p&gt;

&lt;p&gt;As we saw earlier, during the indexing process, Meilisearch identifies all documents that have filterable attributes, such as &lt;code&gt;genre&lt;/code&gt;. Subsequently, it generates a list of document IDs associated with each attribute value, like &lt;code&gt;comedy&lt;/code&gt; or &lt;code&gt;horror&lt;/code&gt;. First of all, when a filter is applied, Meilisearch narrows down the potential results to the document IDs that fulfill the filter criteria.&lt;/p&gt;

&lt;p&gt;Next, it uses the query words and the variations generated in the query graph and searches for matching words in the finite-state transducer (that is, our word dictionary). If the word is considered a prefix, it will also look it up in the prefix FST.&lt;/p&gt;

&lt;p&gt;When encountering words in a FST, it searches them within the inverted index—which contains a mapping of words to document IDs— to retrieve the corresponding document IDs.&lt;/p&gt;

&lt;p&gt;Finally, the engine performs an intersection to identify the documents that contain the words in the query graph and meet the filter criteria.&lt;/p&gt;

&lt;p&gt;Let's take an example to better understand query processing: suppose you have a dataset of songs. The search query is &lt;code&gt;John Lennon&lt;/code&gt;. The user wants to retrieve only songs released between 1957 and 1975.&lt;/p&gt;

&lt;p&gt;First, Meilisearch retrieves the document IDs of songs within that time frame. Then, after checking in the FST that the words in the query graph exist, Meilisearch retrieves the IDs of the documents that contain either &lt;code&gt;John&lt;/code&gt;, &lt;code&gt;Lennon&lt;/code&gt;, or both. It also retrieves the possible variations, but we are not including them in this example for the sake of simplicity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aMY3Ruhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9fw3gn9o5pbb2c38esn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aMY3Ruhe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9fw3gn9o5pbb2c38esn.png" alt='Three Venn diagrams illustrating the process of retrieving songs released based on a user query (John Lennon) with a date filter (between 1057 and 1975). Diagram 1: Represents songs released between 1957 and 1975. Diagram 2: Represents songs with "John" and/or "Lennon" in the title. Diagram 3: Represents the intersection between the two previous diagrams.' width="744" height="874"&gt;&lt;/a&gt;&lt;/p&gt;
Diagrams illustrating the operations involved in retrieving documents based on a user query.



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Finally, the intersection of the two sets of document IDs is taken (the purple area in the diagram.) This means only document IDs that appear in both sets are kept. In other words, Meilisearch retains the document IDs of songs released between 1957 and 1975 that contain either &lt;code&gt;John&lt;/code&gt;, &lt;code&gt;Lennon&lt;/code&gt;, or both.&lt;/p&gt;

&lt;p&gt;What happens when several documents match the search query, how does the engine decide which one to return first? Which one is more relevant? Let's explore the rules allowing Meilisearch to determine how to rank results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relevancy
&lt;/h3&gt;

&lt;p&gt;As we discussed earlier, the query graph includes possible variations of words. As a result, Meilisearch will also return documents with an artist, such as &lt;em&gt;John Lebon&lt;/em&gt;, as part of the search results.&lt;/p&gt;

&lt;p&gt;Fortunately, the query graph not only accounts for word variations but also assigns them the Levenshtein cost, which, among other factors, helps Meilisearch determine the relevancy of the search results.&lt;/p&gt;

&lt;p&gt;Meilisearch sorts documents in the search results using &lt;a href="https://dev.toJohn%20Lebon"&gt;bucket sort&lt;/a&gt;. This algorithm allows ranking documents based on a set of consecutive rules. By default, Meilisearch prioritizes rules as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Words: sorts documents based on the number of matched query terms, with documents containing all query terms ranked first
&lt;/li&gt;
&lt;li&gt;Typo: sorts documents based on the number of typos, with documents matching query terms with fewer typos ranked first&lt;/li&gt;
&lt;li&gt;Proximity: sorts documents based on the distance between matched query terms. Documents where query terms occur close together and in the same order as the query string are ranked first&lt;/li&gt;
&lt;li&gt;Attribute: sorts documents based on the ranking order of attributes. Documents containing query terms in more important attributes are ranked first. Documents with query words at the beginning of attributes are considered more relevant than those with query words at the end&lt;/li&gt;
&lt;li&gt;Sort: sorts documents based on the user-defined parameters set at query time, if active&lt;/li&gt;
&lt;li&gt;Exactness: sorts documents based on the similarity of matched words with the query words&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Meilisearch applies these rules sequentially, sorting results step by step. If two documents are tied after one rule, it uses the next rule to break the tie.&lt;/p&gt;

&lt;p&gt;👉 Note that these rules are fully customizable, meaning you can add, delete, and reorder them as needed. Read more in the &lt;a href="https://www.meilisearch.com/docs/learn/core_concepts/relevancy#ranking-rules"&gt;relevancy documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By default, Meilisearch returns up to 1000 documents per search, prioritizing delivery of the most relevant results rather than all matching results. In other words, Meilisearch prioritizes efficiency and relevance over exhaustive results to ensure an optimized search experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Search engines are complex systems that encompass multiple interconnected components, all working together to deliver a seamless search experience. While the inner workings may differ among search engines, we have explored the underlying mechanisms that power a modern search engine.&lt;/p&gt;

&lt;p&gt;Meilisearch is currently exploring the vast realm of &lt;strong&gt;&lt;a href="https://github.com/meilisearch/meilisearch/issues/3838?ref=blog.meilisearch.com"&gt;semantic search&lt;/a&gt;&lt;/strong&gt;. AI-powered search is reshaping the way we understand queries and documents, opening up new possibilities and use cases. If you’re eager to experience it firsthand, we invite you to try our &lt;a href="https://github.com/meilisearch/product/discussions/677"&gt;vector search experimental feature&lt;/a&gt;—your feedback would be greatly valuable!&lt;/p&gt;

&lt;p&gt;Meilisearch is an open-source search engine that not only provides state-of-the-art experiences for end users but also a simple and intuitive developer experience. Do you want to see Meilisearch in action? Try our &lt;a href="https://where2watch.meilisearch.com/"&gt;demo&lt;/a&gt;. You can also &lt;a href="https://www.meilisearch.com/docs/learn/getting_started/quick_start"&gt;run it locally&lt;/a&gt; or create an account on &lt;a href="https://cloud.meilisearch.com/"&gt;Meilisearch Cloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more things Meilisearch, you can join the community on &lt;a href="https://discord.gg/meilisearch/"&gt;Discord&lt;/a&gt; or subscribe to the &lt;a href="https://meilisearch.us2.list-manage.com/subscribe?u=27870f7b71c908a8b359599fb&amp;amp;id=79582d828e"&gt;newsletter&lt;/a&gt;. You can learn more about the product by checking out the &lt;a href="https://roadmap.meilisearch.com/"&gt;roadmap&lt;/a&gt; and participating in &lt;a href="https://github.com/meilisearch/product/discussions"&gt;product discussions&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>algorithms</category>
      <category>database</category>
    </item>
    <item>
      <title>Prose linting with Vale</title>
      <dc:creator>Maryam</dc:creator>
      <pubDate>Mon, 06 Mar 2023 12:39:45 +0000</pubDate>
      <link>https://dev.to/meilisearch/prose-linting-with-vale-5hj3</link>
      <guid>https://dev.to/meilisearch/prose-linting-with-vale-5hj3</guid>
      <description>&lt;p&gt;Writing is a time-consuming process. Depending on the writer and the review process, it can take a while to get content ready for publication. Whether you’re a solo writer or a big team, prose linters can help ensure a consistent tone and style.&lt;/p&gt;

&lt;p&gt;Similar to code linters, prose linters automatically check your text for errors. Unlike grammar checkers, which highlight violations of grammatical rules, prose linters focus on how you can make your text better by addressing common usage problems like extra spaces, repeated words, excessive use of jargon, sexist language, and incorrect capitalization.&lt;/p&gt;

&lt;p&gt;Prose linters can also provide a framework for creating and enforcing an &lt;a href="https://www.writethedocs.org/guide/writing/style-guides"&gt;editorial style guide&lt;/a&gt;. This helps with the review process as you can now focus on reviewing the content itself instead of pointing out typos and preferred usage patterns. This is particularly important when working in open-source projects like Meilisearch, where you have many contributors unfamiliar with your style guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Vale?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vale.sh/docs/vale-cli/overview"&gt;Vale&lt;/a&gt; is an open-source, highly customizable, syntax-aware prose linter. It supports documents written in many different formats such as Markdown, HTML, reStructuredText, AsciiDoc, DITA, and XML.&lt;/p&gt;

&lt;p&gt;Vale isn’t your only option when it comes to prose linting. There are many other open-source tools available, including &lt;a href="http://proselint.com"&gt;proselint&lt;/a&gt;, &lt;a href="https://textlint.github.io"&gt;textlint&lt;/a&gt;, and &lt;a href="https://alexjs.com"&gt;alex&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At Meilisearch, we decided to go with Vale because it’s fast, easy to set up, flexible, and comes with existing rules to help you get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do I start?
&lt;/h2&gt;

&lt;p&gt;Though it may seem daunting, setting up Vale can be fairly straightforward if you start small and keep things simple. In this post, we’ll go over how to use Vale in a project much like &lt;a href="https://github.com/meilisearch/documentation"&gt;Meilisearch’s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Style guide
&lt;/h3&gt;

&lt;p&gt;The first step is to create a style guide. A style guide ensures a consistent tone and style regardless of how big your team gets. It establishes standard practices when people may have different opinions, such as whether or not to use the oxford comma.&lt;/p&gt;

&lt;p&gt;If you don’t have an in-house style guide, you can check out &lt;a href="https://developers.google.com/style"&gt;Google’s&lt;/a&gt; or &lt;a href="https://learn.microsoft.com/en-us/style-guide/welcome"&gt;Microsoft’s&lt;/a&gt; to help you get started. Over time you will memorize most of the rules, but it’s possible to overlook mistakes and sometimes forget the rules altogether. We’re only human.&lt;/p&gt;

&lt;p&gt;And that is where Vale comes in. It allows you to “codify” a style guide and checks your text against all the rules in that style guide. If it detects any issues, it displays suggestions, warnings, or errors on the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KG3BcvIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34zw6a84618pv5jz37l5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KG3BcvIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34zw6a84618pv5jz37l5.png" alt="Vale output showing errors, warnings, and suggestions" width="880" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Vale
&lt;/h3&gt;

&lt;p&gt;I’m using macOS and ran &lt;code&gt;brew install vale&lt;/code&gt; in my console to install Vale.&lt;/p&gt;

&lt;p&gt;If you’re using a different operating system, check out Vale’s documentation for &lt;a href="https://vale.sh/docs/vale-cli/installation"&gt;installation instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Verify the installation by typing  &lt;code&gt;vale -v&lt;/code&gt; in your console. If this command returns Vale’s version number, the installation was successful.&lt;/p&gt;

&lt;p&gt;Finally, create the following files and folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── .vale.ini
│   ├──  styles
│   │       ├── Style guide
│   │       └── Vocab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Configuring Vale - vale.ini
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;vale.ini&lt;/code&gt; file at the root of your repository. This is the Vale configuration file where you define what you want Vale to do and what files to lint. Let’s start with a basic setup—you can always add to it later based on your project’s needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StylesPath = .vale/styles
MinAlertLevel = suggestion

Vocab = word_list

[*.md]
BasedOnStyles = Meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;StylesPath&lt;/code&gt; is where Vale looks for your style guide (more on that in the next step). The path can be relative or absolute to the location of the &lt;code&gt;vale.ini&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MinAlertLevel&lt;/code&gt; specifies the minimum alert level that Vale will report. By default, it’s set to &lt;code&gt;warning&lt;/code&gt;. The other options are &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;suggestion&lt;/code&gt;.
An error indicates you did something wrong, like using extra spaces or making a typo. A warning isn’t as severe as an error, but indicates something you should avoid, like making sure your sentences don’t become too long. A suggestion is a recommendation to do something that is usually—but not always—a good idea, like breaking your sentence into two instead of using a semicolon.
If a rule is set to &lt;code&gt;suggestion&lt;/code&gt;, you will see suggestions, warnings, and errors. If it is set to &lt;code&gt;warning&lt;/code&gt;, Vale will only show errors and warnings, no suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Vocab&lt;/code&gt;: This is where you create a directory containing the &lt;code&gt;accept.txt&lt;/code&gt; and &lt;code&gt;reject.txt&lt;/code&gt; files. Both files accept words, phrases, and &lt;a href="https://ubuntu.com/blog/regex-basics"&gt;regular expressions&lt;/a&gt;. If your text contains words that do not exist in the dictionary (e.g. “Meilisearch”), you can add them to &lt;code&gt;accept.txt&lt;/code&gt; and Vale won’t angrily scream at you for making a “typo”. Vale will flag all occurrences listed in &lt;code&gt;reject.txt&lt;/code&gt; as errors. This can be useful when you want writers to avoid a specific word—if you are writing about search engines and databases, for example, using “indexation” can be confusing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[*.md]&lt;/code&gt; tells Vale to only lint markdown files. If you want to lint plain text files, use &lt;code&gt;[*.txt]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BasedOnStyles&lt;/code&gt; specifies the style guide Vale should use for linting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can specify other settings, including what tokens and HTML tags to ignore and what Vale should consider an individual word. You can read more about the &lt;code&gt;vale. ini&lt;/code&gt; file in &lt;a href="https://vale.sh/docs/topics/config"&gt;Vale’s documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Rules and the styles folder
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, you need a style guide to use Vale. You then convert this style guide into something Vale can understand: rules.&lt;/p&gt;

&lt;p&gt;Rules use different &lt;a href="https://vale.sh/docs/topics/styles"&gt;extension points&lt;/a&gt; to perform specific tasks. For example, the &lt;code&gt;existence&lt;/code&gt; extension point looks for the existence of a particular token, &lt;code&gt;repetition&lt;/code&gt; looks for repeated tokens, &lt;code&gt;spelling&lt;/code&gt; implements spell checking, and so on. In Vale, each rule is a YAML file. The &lt;code&gt;styles&lt;/code&gt; folder contains the individual rules that make up the style guide.&lt;/p&gt;

&lt;p&gt;If you don’t want to create your own style guide or need a starting point to build from, Vale comes with ready-to-use style guides that you can apply to your docs and start linting. Here are some style guides that helped us get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/errata-ai/Google"&gt;Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/.vale/gitlab"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/redhat-documentation/vale-at-red-hat/tree/main/.vale/styles/RedHat"&gt;RedHat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find more on &lt;a href="https://github.com/errata-ai/packages"&gt;Vale’s GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s start with a rule for sentence length. Your style would say something like, “Ensure sentences don’t exceed 40 words”. This is what the rule looks like as a YAML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Warning: Meilisearch.SentenceLength

# Counts words in a sentence and alerts if a sentence exceeds 40 words.

extends: occurrence
message: 'Shorter sentences improve readability (max 40 words).'
scope: sentence
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#language
level: warning
max: 40
token: \b(\w+)\b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rule counts the words in a sentence and throws a warning if it exceeds 40 words. The &lt;code&gt;scope&lt;/code&gt; is set to &lt;code&gt;sentence&lt;/code&gt;: this ensures that Vale does not apply this rule to other parts of the text, like headings or tables.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;level&lt;/code&gt; is set to &lt;code&gt;warning&lt;/code&gt;. Written text is complicated, and Vale will find false positives. There are no sure-fire ways of deciding when a rule should be a suggestion, warning, or an error. You will need to make decisions and learn as you go.&lt;/p&gt;

&lt;p&gt;I suggest reviewing your rules over time to update and, in some cases, delete outdated rules. Initially, the Meilisearch docs didn’t have a rule on sentence length. When we added it, the maximum length of a sentence was 45. Now it’s 40, and we plan on bringing it down to 35.&lt;/p&gt;

&lt;p&gt;You can also enable or disable specific rules within a style guide by adding them to &lt;code&gt;vale.ini&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Meilisearch.Headings = NO
Meilisearch.Spelling = NO
Meilisearch.Semicolons = NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above lines disable the Heading, Spelling, and Semicolons rules from the &lt;a href="https://github.com/meilisearch/documentation/tree/main/.vale/styles"&gt;Meilisearch style guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Run Vale
&lt;/h3&gt;

&lt;p&gt;Now, when you use the following command on your console to lint your whole project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vale .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vale will check all your files against the rules stored in &lt;code&gt;BasedOnStyles&lt;/code&gt;. If Vale detects any issues, it will display suggestions, warnings, and errors on the console.&lt;/p&gt;

&lt;p&gt;You can also lint individual files using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vale {file_path}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Automate Vale checks
&lt;/h3&gt;

&lt;p&gt;All the checks we’ve discussed so far are for your local files. Once you’re confident the rules work as intended, you can automate these checks using the &lt;a href="https://github.com/errata-ai/vale-action"&gt;Vale GitHub action&lt;/a&gt;! At the Meilisearch documentation repository, we configured it to run for every pull request. As mentioned before, Vale may find false positives. Since you don’t want a PR blocked because Vale isn’t working as it should, I recommend starting with a few rules, and slowly tweaking them to avoid failing checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That is all, folks! I hope I was able to help you get started with Vale (and a style guide). This was a quick overview to introduce you to Vale’s features. Tweaking it to your needs takes time and many, &lt;em&gt;many&lt;/em&gt; iterations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nQS5rcxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy451v4nhu8k68vv88d1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nQS5rcxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy451v4nhu8k68vv88d1.gif" alt="Tired brain" width="496" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once configured, Vale can automate parts of the review process and allow you to focus on the parts of a text that computers are not very good at. At least not yet.&lt;/p&gt;

&lt;p&gt;Oh, and if you’re curious, check out &lt;a href="https://github.com/meilisearch/documentation/tree/main/.vale/styles"&gt;our style guide on GitHub&lt;/a&gt; to see how we use Vale!&lt;/p&gt;

</description>
      <category>vale</category>
      <category>proselinter</category>
      <category>styleguide</category>
    </item>
    <item>
      <title>Meilisearch 1.0: the next stage in search</title>
      <dc:creator>Guillaume Mourier</dc:creator>
      <pubDate>Tue, 21 Feb 2023 13:01:07 +0000</pubDate>
      <link>https://dev.to/meilisearch/meilisearch-10-the-next-stage-in-search-nn8</link>
      <guid>https://dev.to/meilisearch/meilisearch-10-the-next-stage-in-search-nn8</guid>
      <description>&lt;p&gt;After three years of hard work and dedication, we are thrilled to announce the &lt;strong&gt;launch of Meilisearch 1.0&lt;/strong&gt;. With this release, Meilisearch has taken a stride forward in its mission to help developers create fast, powerful, and reliable search experiences.&lt;/p&gt;

&lt;p&gt;With more than 32,000 GitHub stargazers and 100,000 launches per month, Meilisearch is already well-loved by its community. Now, after countless hours spent polishing the API and architecture to perfection, we are confident and happy to release the first completely stable version of Meilisearch, with guaranteed compatibility through future versions.&lt;/p&gt;

&lt;p&gt;Creating a seamless search experience for your users can be a daunting task, but it is crucial to help your business &lt;strong&gt;elevate user satisfaction, drive conversions, and increase retention&lt;/strong&gt;. Enter &lt;strong&gt;Meilisearch v1&lt;/strong&gt;: the most performant search engine on the market with zero setup required.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Meilisearch?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Meilisearch is an open-source, user-focused search engine&lt;/strong&gt; that easily integrates with any website or application. It features powerful built-in capabilities such as &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/features.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=search-as-you-type#search-as-you-type"&gt;search-as-you-type&lt;/a&gt;, &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/features.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=typo-tolerant#typo-tolerant"&gt;typo tolerance&lt;/a&gt;, &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/features.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=faceted-search#faceting"&gt;faceted search&lt;/a&gt;, &lt;a href="https://docs.meilisearch.com/learn/advanced/geosearch.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=geosearch"&gt;geo search&lt;/a&gt;, and &lt;a href="https://docs.meilisearch.com/learn/security/tenant_tokens.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=multitenancy"&gt;multi-tenancy&lt;/a&gt;. A suite of &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/sdks.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=integrations"&gt;SDKs and libraries&lt;/a&gt; makes it easy to connect with popular coding languages and web tools. When it comes to languages, Meilisearch supports them all, with special optimizations for any language that uses whitespace to separate words, plus Chinese, Japanese, Hebrew, Thai, and Korean.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We found that, with our prior search engine *&lt;/em&gt;(Elasticsearch), 14%** of searches resulted in a purchase, and with &lt;strong&gt;Meilisearch, 20%&lt;/strong&gt; of searches were resulting in a purchase. That's a &lt;strong&gt;huge improvement&lt;/strong&gt; without a lot of development time: 1 out of 5 customers found the book they were looking for and purchased it.&lt;br&gt;
- Andy Hunter, CEO of &lt;a href="https://bookshop.org/"&gt;Bookshop.org&lt;/a&gt;*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From e-commerce to SaaS, media, and beyond, businesses from all industries trust Meilisearch to power their search needs. Don't let lackluster search hold you back any longer: &lt;a href="https://www.meilisearch.com/?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=landing"&gt;try Meilisearch today&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do companies love Meilisearch?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Simplicity
&lt;/h3&gt;

&lt;p&gt;We're a team of developers who understand the importance of a great developer experience. Even if you have the most flexible and powerful tool in the world, it doesn’t count for much if it’s painful to use and understand. That's why we made Meilisearch: to give developers the tool they need to create awesome search experiences, without provoking headaches or gray hairs.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;consistency&lt;/strong&gt; and &lt;strong&gt;predictability&lt;/strong&gt; of Meilisearch’s design make it easy to integrate into your chosen technical stack. Our comprehensive &lt;a href="https://docs.meilisearch.com/?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=docs"&gt;documentation&lt;/a&gt; and &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/sdks.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=integrations2"&gt;developer tools&lt;/a&gt; are designed to help you from start to success.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meilisearch works out of the box with no configuration needed&lt;/strong&gt;. But we understand that every project is different, so we've made customization easy. You can tailor it to your needs in just a few minutes, so you don't have to be a search expert to get the most out of Meilisearch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relevancy
&lt;/h3&gt;

&lt;p&gt;Relevancy, meaning the quality and accuracy of the search results, is a crucial aspect of any search engine. Irrelevant or poor-quality results can lead to a poor user experience, reducing sales, and causing users to lose trust in your brand. Conversely, users are more likely to return to, trust, and engage with brands that provide relevant search experiences.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;As a user, it felt like magic compared to other solutions I've tried. I'm not sure whether it's related to how typo tolerance works or if it's related to the default settings. Still, right after setting up Meilisearch with no particular tweak, I've got fantastically relevant results.&lt;br&gt;
- Anthony Catel, Co-founder of &lt;a href="https://www.minipouce.fr/"&gt;minipouce&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Meilisearch provides a &lt;strong&gt;pre-configured set of ranking rules&lt;/strong&gt; that enable you to achieve &lt;strong&gt;high relevancy right out of the box&lt;/strong&gt;, while also accepting customization to meet individual needs. These default settings were developed iteratively by working directly with our users, and are sure to satisfy almost all use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;In today's fast-paced digital world, search plays a crucial role in user experience. Being able to deliver relevant results quickly is key to the success of almost any product.&lt;/p&gt;

&lt;p&gt;One &lt;a href="https://www2.deloitte.com/content/dam/Deloitte/ie/Documents/Consulting/Milliseconds_Make_Millions_report.pdf"&gt;report from Deloitte&lt;/a&gt; shows that a mere 0.1s change in load time can have a noticeable influence on the user journey, increasing conversions by 8% for retail sites and 10% for travel sites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meilisearch returns results in as little as 0.05s&lt;/strong&gt;. It is designed from the ground up for performance, making it an essential addition to your technical stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s included?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Search-as-you-type
&lt;/h3&gt;

&lt;p&gt;For a long time, users were accustomed to typing search queries, pressing enter, and waiting for a page to load to view results. Those days are over, as technological improvements have ushered in the age of “search-as-you-type.”&lt;/p&gt;

&lt;p&gt;By providing results instantly as the user types their query, &lt;strong&gt;Meilisearch helps users make more precise searches and quickly find what they are looking for&lt;/strong&gt;. In today’s internet, “search-as-you-type” is a must-have feature that greatly improves overall satisfaction and retention.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typo tolerance
&lt;/h3&gt;

&lt;p&gt;Typos happen. &lt;a href="https://blog.google/products/search/abcs-spelling-google-search/"&gt;According to the VP of Search at Google&lt;/a&gt;, as many as 1 in 10 searches are misspelled. &lt;a href="https://baymard.com/research/ecommerce-search"&gt;A Baymard Institute UX study&lt;/a&gt; also reports that out of 185 major e-commerce sites, 34% don’t return useful results when users misspell even a single character in a product title.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dGuYNGh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44rbyphzrzzog4dswowb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dGuYNGh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44rbyphzrzzog4dswowb.gif" alt="" width="800" height="385"&gt;&lt;/a&gt;&lt;a href="https://where2watch.meilisearch.com/?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=where2watch"&gt;See Meilisearch in action here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These statistics highlight the importance of using a search solution that can effectively handle spelling mistakes. &lt;strong&gt;Meilisearch’s customizable typo tolerance allows for more accurate and relevant search results&lt;/strong&gt; even when users don’t type perfectly. Even better, it isn’t limited to Latin-based languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Faceted search
&lt;/h3&gt;

&lt;p&gt;E-commerce merchants with large catalogs have a particular challenge to overcome. Potential buyers can get &lt;a href="https://neilpatel.com/blog/too-many-choices/"&gt;overwhelmed by possibilities&lt;/a&gt;, becoming less likely to make a purchase simply due to the effort of making a decision.&lt;/p&gt;

&lt;p&gt;Fortunately, faceted search interfaces solve this problem.&lt;/p&gt;

&lt;p&gt;Faceted search is a powerful tool that gives customers the power to apply filters and narrow down search results based on their needs and desires. By helping shoppers view the products they’re looking for based on criteria such as size, color, and style, the likelihood of a purchase is increased.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meilisearch makes it easy to integrate faceted search into any e-commerce storefront&lt;/strong&gt;. With just a few lines of code, you can upgrade your store's search capabilities, increasing sales and customer satisfaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Geo search
&lt;/h3&gt;

&lt;p&gt;Geo search, also known as location-based search or local search, is becoming increasingly important for modern web applications. With the fast-paced nature of today's world, people are constantly on the move and looking for quick and easy ways to find the information they need, such as &lt;strong&gt;nearby businesses, services, or other points of interest&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meilisearch meets this need, providing simple methods to &lt;a href="https://docs.meilisearch.com/learn/advanced/geosearch.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=geosearch2"&gt;sort search results by their location or filter results based on a geographic radius&lt;/a&gt;. This helps developers build more personalized and modern applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  API keys and multi-tenant indexes
&lt;/h3&gt;

&lt;p&gt;Thanks to &lt;a href="https://docs.meilisearch.com/learn/security/master_api_keys.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=API-key-management"&gt;fine-grained API key management&lt;/a&gt;, you can personalize &lt;strong&gt;Meilisearch to comply with your organization’s security requirements&lt;/strong&gt;. Create API keys with custom permissions and expiration dates to ensure secure and flexible access to your data.&lt;/p&gt;

&lt;p&gt;If your application is storing sensitive data from multiple users in the same index, it's very important that each user can only search for their own documents. You can trust Meilisearch’s many SDKs to provide methods to generate &lt;a href="https://docs.meilisearch.com/learn/security/tenant_tokens.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=multitenancy2"&gt;tenant tokens&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;We will stay devoted to our core concepts of simplicity, speed, and relevance to keep empowering all builders.&lt;/p&gt;

&lt;p&gt;We’ll keep collaborating with the open-source community and focusing on the Developer Experience to ensure &lt;strong&gt;Meilisearch users can provide the best search experience in their websites and applications&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start building with Meilisearch v1.0
&lt;/h2&gt;

&lt;p&gt;You can &lt;strong&gt;get started with Meilisearch in just a few minutes&lt;/strong&gt;—everything works out of the box, no configuration required! All you need to do is choose the hosting solution that fits your business requirements, add documents, and you’re off.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try our solution: Meilisearch Cloud
&lt;/h3&gt;

&lt;p&gt;Need to build fast, be compliant, or save resources? &lt;a href="https://www.meilisearch.com/pricing?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=cloud"&gt;Meilisearch Cloud&lt;/a&gt; takes care of everything, so you can focus on the most important thing: making your users happy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build your own solution: self-hosting
&lt;/h3&gt;

&lt;p&gt;Since Meilisearch is open-source, you can host your own Meilisearch instance. Run Meilisearch and start searching through your data in less than five minutes by following our &lt;a href="https://docs.meilisearch.com/learn/getting_started/quick_start.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=quick-start"&gt;quick start guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;🧰 For both solutions, we provide a large number of &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/sdks.html?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=integrations3"&gt;developer tools&lt;/a&gt; and &lt;a href="https://docs.meilisearch.com/?utm_source=release-post&amp;amp;utm_id=v1-announcement&amp;amp;utm_content=docs2"&gt;reliable documentation&lt;/a&gt; to help you connect your code base with Meilisearch.&lt;/p&gt;

</description>
      <category>search</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Navigating search results: pagination vs infinite scroll vs load more</title>
      <dc:creator>Maryam</dc:creator>
      <pubDate>Thu, 15 Dec 2022 13:00:01 +0000</pubDate>
      <link>https://dev.to/meilisearch/navigating-search-results-pagination-vs-infinite-scroll-vs-load-more-m90</link>
      <guid>https://dev.to/meilisearch/navigating-search-results-pagination-vs-infinite-scroll-vs-load-more-m90</guid>
      <description>&lt;p&gt;Meilisearch v0.30 is out and brings with it the ability to create numbered page selectors. You can read more about the new features and updates from v0.30 in our &lt;a href="https://blog.meilisearch.com/whats-new-in-v0-30/" rel="noopener noreferrer"&gt;release blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article will go over the different ways of navigating search results and the pros and cons of each method.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is pagination, and what are some common alternatives?
&lt;/h2&gt;

&lt;p&gt;Let’s say you go to an ecommerce website to buy a new pair of shoes. It would be quite overwhelming if you got 700 pairs of shoes to choose from as soon as the page loads—not to mention that fetching every pair of shoes would certainly slow down the site.&lt;/p&gt;

&lt;p&gt;To avoid this, most websites will break search results up into chunks, such as pages, and load a certain number at a time based on input from the user.&lt;/p&gt;

&lt;p&gt;There are three main ways to display large datasets: pagination, infinite scroll, and load more. Each method has benefits and downsides that make it suited for certain use cases and content types. For example, Google’s use of numbered pagination makes it easier to find a specific result again, while Twitter, Facebook, and Instagram use infinite scroll to keep users glued to their screens. Google uses load more on mobile devices to display search results.&lt;/p&gt;

&lt;p&gt;Changing from one type of pagination to another can completely alter user experience.  Imagine waking up to a paginated version of Twitter, where you have to continuously click a “Next” button to view more posts in your feed (thanks, Elon). This would completely change the way you interact with the site!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa172aijbnmyvxbfj9hl1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa172aijbnmyvxbfj9hl1.gif" alt="Image description" width="498" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In making the choice of how to display search results, you decide how much content to show users at one time, what action they have to take to view more, and how convenient it is to find a specific result again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pagination
&lt;/h2&gt;

&lt;p&gt;Pagination works by breaking search results down into separate pages. There are two main types of pagination interfaces: numbered ones, where you find a list of numbered pages at the bottom of each page, and unnumbered ones, where you navigate from page to page using the “Previous” and “Next” buttons.&lt;/p&gt;

&lt;p&gt;Pagination is one of the most popular ways to display search results and is particularly common on ecommerce websites. Pagination breaks down content, making it easier to process. Since each page is distinct, users can easily return to items they liked or share them with others. This helps users to search for something specific instead of browsing through a never-ending list of items.&lt;/p&gt;

&lt;p&gt;The biggest downside to pagination is that most users don’t look beyond the first few pages and hence never get to look at more results. When was the last time you went to the second page of Google’s search results?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3mdcxokyo2iym1j9vf5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3mdcxokyo2iym1j9vf5.gif" alt="Thinking Pooh" width="498" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the results are replaced with every new page, users need to switch between pages to compare results. In addition, pagination isn’t very mobile-friendly. Mobile users prefer load more or infinite scroll as it’s more intuitive. It also requires additional actions from the user: clicking the “Next” button and waiting for the page to load. This may also give the impression that pagination is slow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Numbered page selection
&lt;/h3&gt;

&lt;p&gt;Page numbers add clarity to the search process and guide users to what they’re searching for. Numbered page selection offers numerous advantages, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users can be shown the total number of pages of results, allowing them to estimate how long they will need to find a particular item. (“I have 25 pages worth of shoes to sift through!”)&lt;/li&gt;
&lt;li&gt;With numbered pages, it’s clear that some pages are more relevant than others. (“I didn’t find those shoes on the first five pages, so this website probably doesn’t sell them.”)&lt;/li&gt;
&lt;li&gt;Users can remember the positioning of an item, and numbered pages allow them to return to it faster. (“I liked the pink shoes on page 3.”)&lt;/li&gt;
&lt;li&gt;Users can generally stop in the middle of a session and continue from where they left off. (“I stopped at page 5 yesterday.”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgu0k6khznr9swzrcwr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgu0k6khznr9swzrcwr9.png" alt="Numbered pagination" width="718" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  “Previous” and “Next” buttons
&lt;/h3&gt;

&lt;p&gt;In numberless pagination, users navigate via “Next” and “Previous” buttons instead of a list of numbered pages. This alternative to numbered pagination is often used for mobile displays where there isn’t enough space to display page numbers. Since there are only two buttons, it offers less precision, as users can’t jump to specific pages. However, it offers better performance as it isn’t necessary to calculate the total number of search results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcs9y65xvr54jslr14zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcs9y65xvr54jslr14zv.png" alt="" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Infinite scroll
&lt;/h2&gt;

&lt;p&gt;Infinite scroll has become increasingly popular over the past decade due to the rise in smartphones. It loads more content seamlessly as the user scrolls, reducing friction. It’s also more intuitive than pagination; you just keep scrolling to view more content! Additionally, since all the content is loaded to a single page, it may seem faster than traditional pagination.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb08fgmdjl7p2nxw26rqh.GIF" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb08fgmdjl7p2nxw26rqh.GIF" alt="Infinite scroll gif" width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The biggest downside to infinite scroll is poor usability.  The page length increases infinitely, making it difficult to find previously viewed results again, nor can users bookmark or share a particular set of items on the list.  Page performance slows down as more content is loaded, making the page “heavier”. Meanwhile, the site footer may be inaccessible since infinite scroll pushes it endlessly down as more content is loaded. Since Googlebot cannot emulate scrolling, infinite scroll also has a negative impact on SEO.&lt;/p&gt;

&lt;p&gt;However, the greatest impact by far is on user behavior. At some point, users of infinite scroll will stop paying attention to individual results and begin to focus more on scrolling, leading to decreased engagement. You can read more about this in &lt;a href="https://www.smashingmagazine.com/2016/03/pagination-infinite-scrolling-load-more-buttons/" rel="noopener noreferrer"&gt;Baymard Institute's study&lt;/a&gt; on design patterns for loading products on desktops and mobile devices.&lt;/p&gt;

&lt;p&gt;Based on the above, infinite scroll may not be the best solution for ecommerce websites. How do you find the pink shoes you liked 15-ish scrolls ago?&lt;/p&gt;

&lt;p&gt;There is one use case where infinite scroll cannot be beat. For entertainment websites whose main purpose is to keep the users with no particular aim on the page for as long as possible, infinite scroll all but guarantees a longer time on site. This is why infinite scroll is closely linked with social media and other business models that rely on advertising or data harvesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load more
&lt;/h2&gt;

&lt;p&gt;Like infinite scroll, load more is a mobile-friendly option that works by extending one page infinitely. However, unlike infinite scroll, load more allows users to choose whether they want to view more results by clicking a “Load more” button at the bottom of the page. This critical difference gives users more control, making it easier, for example, to access the footer or keep track of a specific result. Studies show that it also increases the amount of attention users give to each individual item.&lt;/p&gt;

&lt;p&gt;Load more shares many downsides with infinite scroll, such as poor page performance. Like infinite scroll, it’s not ideal for SEO as Googlebot cannot click the “Load more” button. This means it cannot crawl or index all of your content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3585dkshtt7g4o1tqmal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3585dkshtt7g4o1tqmal.png" alt="Load more pagination" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, what do I use?
&lt;/h2&gt;

&lt;p&gt;The short answer: it depends on the kind of product experience you want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pagination&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your users are looking for highly specific results&lt;/li&gt;
&lt;li&gt;SEO is very important to you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Infinite scroll&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’re building a social media site&lt;/li&gt;
&lt;li&gt;Your users want to explore a large amount of content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Load more&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to hide your content behind a paywall&lt;/li&gt;
&lt;li&gt;You want to build an ethical mobile experience&lt;/li&gt;
&lt;li&gt;You want to gain some of the benefits of both pagination and infinite scroll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or you could go hybrid! Consider Ikea: they use a load more button but also display the total number of search results and a progress bar, enabling users to see how many results they’ve viewed so far.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9vlfnyy6gcf9e8ur947.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9vlfnyy6gcf9e8ur947.png" alt="Hybrid pagination" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While we have covered the three main ways to display search results today, they are far from set in stone. At the end of the day, your goal is to help your users find the content they need. If you understand which key goals you want to accomplish with your search navigation interface and which pitfalls you want to avoid, you may be able to design something even better than what’s been done before. Good luck, and let us know what you create with Meilisearch!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to integrate an extremely fast and relevant search into your Rails app using Meilisearch and React</title>
      <dc:creator>Carolina</dc:creator>
      <pubDate>Thu, 01 Sep 2022 12:12:34 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-integrate-an-extremely-fast-and-relevant-search-into-your-rails-app-using-meilisearch-and-react-3g36</link>
      <guid>https://dev.to/meilisearch/how-to-integrate-an-extremely-fast-and-relevant-search-into-your-rails-app-using-meilisearch-and-react-3g36</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you'll learn how to integrate Meilisearch with your Rails application database and quickly create a front-end search bar with a search-as-you-type experience using React.&lt;/p&gt;

&lt;p&gt;We will create a very basic application; our main focus will be the search. Therefore we won't go into much detail about Rails or React.&lt;br&gt;
Prerequisites&lt;/p&gt;

&lt;p&gt;To follow this tutorial, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; &amp;gt;=16.10&lt;/li&gt;
&lt;li&gt;    &lt;a href="https://yarnpkg.com/"&gt;yarn&lt;/a&gt; 1&lt;/li&gt;
&lt;li&gt;    &lt;a href="https://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; &amp;gt;= 2.7&lt;/li&gt;
&lt;li&gt;    &lt;a href="https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails"&gt;Ruby on Rails&lt;/a&gt; 7.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ideally, you are familiar with Ruby on Rails and have already created a simple RoR app. If that's not the case, you can still follow this tutorial, but as we stated in the introduction, explanations will focus on the search.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1. Installing Meilisearch
&lt;/h2&gt;

&lt;p&gt;There are &lt;a href="https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch"&gt;several ways&lt;/a&gt; to install Meilisearch. The easiest is &lt;a href="https://curl.se/"&gt;cURL&lt;/a&gt;, a tool that allows you to make HTTP requests and transfer data from the command line.&lt;/p&gt;

&lt;p&gt;Open your terminal and paste the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install Meilisearch
curl -L https://install.meilisearch.com | sh

# Launch Meilisearch
./meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2. Creating and setting up your Rails app
&lt;/h2&gt;

&lt;p&gt;Now that you've got Meilisearch up and running, let's create our RoR app.‌‌ We will create a simple recipe app named &lt;code&gt;delicious_meals&lt;/code&gt;. Run the following command on the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails new delicious_meals -j esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;‌Let's generate our model &lt;code&gt;Recipe&lt;/code&gt;. It will have four attributes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;    &lt;code&gt;title&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;    &lt;code&gt;ingredients&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;    &lt;code&gt;directions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;    &lt;code&gt;diet&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go into the project folder and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/rails g model Recipe title:string ingredients:text directions:text diet:string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command also generates the migration file inside the &lt;code&gt;db/migrate&lt;/code&gt; directory. Let's add the &lt;code&gt;null: false&lt;/code&gt; option next to each column of the table so that no recipe is saved to the database if a field is empty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CreateRecipes &amp;lt; ActiveRecord::Migration[7.0]
  def change
    create_table :recipes do |t|
      t.string :title, null: false
      t.text :ingredients, null: false
      t.text :directions, null: false
      t.string :diet, null: false

      t.timestamps
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;timestamps&lt;/code&gt; column method adds two extra fields to the table: &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can now create the database and run the migration above with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Creates the database 
bin/rails db:create 

# Runs the migration 
bin/rails db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to generate the controller with its &lt;code&gt;index&lt;/code&gt; action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/rails g controller Recipes index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the &lt;code&gt;index&lt;/code&gt; view to show our recipes and search through them with our search bar. We won't generate the rest of the CRUD actions, as it would exceed the purpose of this tutorial.&lt;/p&gt;

&lt;p&gt;Once the controller is created, modify the &lt;code&gt;config/routes.rb&lt;/code&gt; file to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails.application.routes.draw do
  # Maps requests to the root of the application to the index action of the 'Recipes controller'
  root "recipes#index"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;root&lt;/code&gt; route is mapped to the &lt;code&gt;index&lt;/code&gt; action of &lt;code&gt;RecipesController&lt;/code&gt;. That way, the content of &lt;code&gt;app/views/recipes/index.html.erb&lt;/code&gt; will be rendered at the root of your application.&lt;/p&gt;

&lt;p&gt;You can check that everything is working as intended by starting the application with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser window and navigate to &lt;code&gt;http://127.0.0.1:3000&lt;/code&gt;. You should see your index view displaying a message such as:&lt;/p&gt;

&lt;h1&gt;Recipes#index&lt;/h1&gt;

&lt;p&gt;Find me in app/views/recipes/index.html.erb&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Adding Meilisearch to your app
&lt;/h2&gt;

&lt;p&gt;Now that we have the back-end basics of our application, let's connect it to our running Meilisearch instance using the &lt;code&gt;meilisearch-rails&lt;/code&gt; gem.&lt;/p&gt;

&lt;p&gt;Install it by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bundle add meilisearch-rails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 When writing this tutorial, the latest version of the gem was 0.7.1. You can check the latest version in the &lt;a href="https://github.com/meilisearch/meilisearch-rails"&gt;meilisearch-rails GitHub repository&lt;/a&gt; or on &lt;a href="https://rubygems.meilisearch.com/?q=meilisearch-rails"&gt;Meilisearch finds rubygems&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;meilisearch.rb&lt;/code&gt; inside the &lt;code&gt;config/initializers/&lt;/code&gt; folder to setup your &lt;code&gt;MEILISEARCH_HOST&lt;/code&gt; and &lt;code&gt;MEILISEARCH_API_KEY&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch config/initializers/meilisearch.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have followed step 1 to the letter, your Meilisearch host should be &lt;code&gt;http://127.0.0.1:7700&lt;/code&gt;. Since we did not set any API key, we will comment out the line with the &lt;code&gt;meilisearch_api_key field&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MeiliSearch::Rails.configuration = {
    meilisearch_host: 'http://127.0.0.1:7700',
    # meilisearch_api_key: ''
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 You will need a master or a private key in production, you can learn more about it &lt;a href="https://docs.meilisearch.com/reference/features/authentication.html"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you did set a master key, you have to update your configuration accordingly before running Meilisearch (see step 1).&lt;/p&gt;

&lt;p&gt;Let's open our &lt;code&gt;app/models/recipe.rb&lt;/code&gt; file and add the following line inside the &lt;code&gt;Class&lt;/code&gt; declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;include MeiliSearch::Rails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to add a meilisearch block. Note that the settings inside the Meilisearch block are not mandatory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Recipe &amp;lt; ApplicationRecord
    include MeiliSearch::Rails

    meilisearch do
        # all attributes will be sent to Meilisearch if block is left empty
        displayed_attributes [:id, :title, :ingredients, :directions, :diet]
        searchable_attributes [:title, :ingredients, :directions, :diet]
        filterable_attributes [:diet]
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down each line of code:&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting displayed attributes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;displayed_attributes [:id, :title, :ingredients, :directions, :diet]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Meilisearch displays all the attributes. Here, we are instructing Meilisearch to only display the specified attributes in the search response, this setting prevents Meilisearch from displaying the &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;👉 You can learn more about &lt;code&gt;displayed attributes&lt;/code&gt; in our &lt;a href="https://docs.meilisearch.com/reference/features/field_properties.html#displayed-fields"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting searchable attributes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;searchable_attributes [:title, :ingredients, :directions, :diet]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above line of code, we are doing two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We first tell Meilisearch to only search among the specified attributes when performing a search query. So it won't try to find matches in the &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields.&lt;/li&gt;
&lt;li&gt;We are also specifying the order of importance of the attributes. We are telling Meilisearch that a document with a matching query word found in its &lt;code&gt;title&lt;/code&gt; is more relevant than a document with a matching query word found in &lt;code&gt;directions&lt;/code&gt;. The first document is more relevant and is returned first in the search results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 Learn more about &lt;code&gt;searchable fields&lt;/code&gt; in our &lt;a href="https://docs.meilisearch.com/learn/configuration/displayed_searchable_attributes.html#searchable-fields"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting filterable attributes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filterable_attributes [:diet]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we are telling Meilisearch that we want to be able to &lt;strong&gt;refine our search results&lt;/strong&gt; based on the &lt;code&gt;diet&lt;/code&gt; type. That will allow us to search only for vegetarian recipes, for instance.&lt;/p&gt;

&lt;p&gt;👉 Visit our &lt;a href="https://docs.meilisearch.com/reference/features/filtering_and_faceted_search.html"&gt;documentation&lt;/a&gt; to know more about filtering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4. Seeding the database
&lt;/h2&gt;

&lt;p&gt;To test our application, we need some data in our database. The quickest way is to populate the database with dummy data using a gem called &lt;em&gt;&lt;a href="https://github.com/faker-ruby/faker"&gt;faker&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Add the following line to your &lt;code&gt;Gemfile&lt;/code&gt; inside the development group, save and run &lt;code&gt;bundle install&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'faker', :git =&amp;gt; 'https://github.com/faker-ruby/faker.git', :branch =&amp;gt; 'master' 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the &lt;code&gt;./db/seeds.rb&lt;/code&gt; file and add the following code to populate your database with 1000 recipes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Deletes existing recipes, useful if you seed several times
Recipe.destroy_all

# Creates 1000 fake recipes
1000.times do
    Recipe.create!(
        title: "#{Faker::Food.dish} by #{Faker::Name.unique.name}",
        ingredients: "#{Faker::Food.ingredient}, #{Faker::Food.ingredient}, #{Faker::Food.ingredient}",
        directions: Faker::Food.description,
        diet: ['omnivore', 'pescetarian', 'vegetarian', 'vegan'].sample
    )
end 

# Displays the following message in the console once the seeding is done
puts 'Recipes created'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run &lt;code&gt;bin/rails db:seed&lt;/code&gt; in the command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5. Testing search with the search preview
&lt;/h2&gt;

&lt;p&gt;Meilisearch delivers an out-of-the-box web interface to test it interactively. Open your browser and go to the Meilisearch HTTP address, which should be &lt;code&gt;http://127.0.0.1:7700&lt;/code&gt;, unless you specified it otherwise &lt;a href="https://docs.meilisearch.com/learn/configuration/instance_options.html#http-address-port-binding"&gt;at launch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;👉 Adding documents to an index is an asynchronous operation, don't worry if you don't see the 1000 documents right away. It might take some time for the updates to process. Learn more about asynchronous updates &lt;a href="https://docs.meilisearch.com/learn/advanced/asynchronous_updates.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Make sure the &lt;code&gt;Recipe&lt;/code&gt; index is selected in the menu located at the top right, next to the search bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SHxqBFTH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94bg2j6d1yvty9xkroag.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SHxqBFTH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94bg2j6d1yvty9xkroag.gif" alt="Meilisearch mini dashboard" width="880" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the data has been automatically added to our Meilisearch instance. The only visible and searchable attributes are the ones &lt;a href="https://blog.meilisearch.com/how-to-integrate-an-extremely-fast-and-relevant-search-into-your-rails-app-using-meilisearch-and-react/#setting-displayed-attributes"&gt;we specified in our model file&lt;/a&gt; inside the &lt;code&gt;meilisearch block&lt;/code&gt;. Please note that your search results may be different from those shown in the GIF, since faker randomly generates data.&lt;/p&gt;

&lt;p&gt;This is great for testing Meilisearch and some of its features, but it doesn't showcase the &lt;code&gt;filterable_attributes&lt;/code&gt; we specified in our block. We need a custom UI for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6. Adding React to the Rails app
&lt;/h2&gt;

&lt;p&gt;There are several ways of using ReactJS with Rails. We have chosen the most straightforward one: installing it as a JavaScript dependency in our Rails application.&lt;/p&gt;

&lt;p&gt;Run the following command to install &lt;strong&gt;ReactJS&lt;/strong&gt; and its &lt;strong&gt;react-dom&lt;/strong&gt; package for working with the DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react react-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's create the folders and files for our React code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir app/javascript/recipes 
touch app/javascript/recipes/index.jsx 
touch app/javascript/recipes/App.jsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's open &lt;code&gt;app/javascript/recipes/index.jsx&lt;/code&gt; and add the required code to render our React elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('app');
const root = createRoot(container); 
root.render(&amp;lt;App/&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the &lt;code&gt;app/javascript/application.js&lt;/code&gt; and import the file we just created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./recipes"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7. Integrating a front-end search bar
&lt;/h2&gt;

&lt;p&gt;To integrate a front-end search bar, you need to install two packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://github.com/algolia/react-instantsearch"&gt;React InstantSearch&lt;/a&gt;&lt;/strong&gt;: an open-source library that provides all the front-end tools you need to customize your search bar environment&lt;/li&gt;
&lt;li&gt;    &lt;strong&gt;&lt;a href="https://github.com/meilisearch/instant-meilisearch"&gt;Instant Meilisearch&lt;/a&gt;&lt;/strong&gt;: the Meilisearch client to establish the communication between your Meilisearch instance and the React InstantSearch library
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react react-dom react-instantsearch-dom @meilisearch/instant-meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now open your &lt;code&gt;app/javascript/recipes/App.jsx&lt;/code&gt; file and replace the existing code with the code from the &lt;code&gt;meilisearch-react&lt;/code&gt; &lt;a href="https://github.com/meilisearch/meilisearch-react/#getting-started"&gt;Getting Started&lt;/a&gt; guide. We only need to modify the &lt;code&gt;searchClient&lt;/code&gt; with our Meilisearch host and Meilisearch API key, as well as the &lt;code&gt;indexName&lt;/code&gt;. It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { InstantSearch, Highlight, SearchBox, Hits } from 'react-instantsearch-dom';
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch';

const searchClient = instantMeiliSearch(
  "http://127.0.0.1:7700", // Your Meilisearch host
  "" // Your Meilisearch API key, if you have set one
);

const App = () =&amp;gt; (
  &amp;lt;InstantSearch
    indexName="Recipe" // Change your index name here
    searchClient={searchClient}
  &amp;gt;
    &amp;lt;SearchBox /&amp;gt;
    &amp;lt;Hits hitComponent={Hit} /&amp;gt;
  &amp;lt;/InstantSearch&amp;gt;
);

const Hit = ({ hit }) =&amp;gt; &amp;lt;Highlight attribute="title" hit={hit} /&amp;gt;

export default App

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, go to your &lt;code&gt;views&lt;/code&gt; folder and replace the content of the &lt;code&gt;app/views/recipes/index.html.erb&lt;/code&gt; with the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="app"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run the &lt;code&gt;bin/dev&lt;/code&gt; command, open your browser and navigate to &lt;code&gt;http://127.0.0.1:3000&lt;/code&gt; and see the result:‌&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hX6u3e5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1oivxbr4czw4v6yj5upf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hX6u3e5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1oivxbr4czw4v6yj5upf.gif" alt="Typing salad in an unstyled search bar, the results are updated as you type" width="880" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, the search works, but it's not very pretty. Luckily, InstantSearch provides a &lt;a href="https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react/#loading-the-theme"&gt;CSS theme&lt;/a&gt; you can add by inserting the following link into the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element of your &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7.4.5/themes/satellite-min.css" integrity="sha256-TehzF/2QvNKhGQrrNpoOb2Ck4iGZ1J/DI4pkd2oUsBc=" crossorigin="anonymous"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also customize the widgets or create your own if you want to. Check the &lt;a href="https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react/"&gt;React InstantSearch documentation&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;Let's check the rendering:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VvLNS3jx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnvmi7f1h2u3xnl5qpax.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VvLNS3jx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnvmi7f1h2u3xnl5qpax.gif" alt="Typing chicken in a styled search bar, the results are updated as you type" width="880" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not bad, right? But once again we lack the possibility of filtering the results by type of diet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8. Adding faceted search
&lt;/h2&gt;

&lt;p&gt;It's as simple as importing the &lt;code&gt;RefinementList&lt;/code&gt; widget in your &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { InstantSearch, Highlight, SearchBox, Hits, RefinementList } from 'react-instantsearch-dom';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and adding it inside our &lt;code&gt;InstantSearch&lt;/code&gt; widget, specifying the attribute we want to filter by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;RefinementList attribute="diet" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make it more aesthetic and practical, let's create two &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements to divide our components. On the left, we'll find the filters, and the search bar and results on the right.&lt;/p&gt;

&lt;p&gt;You can also add a "Type of diet" heading along with the &lt;code&gt;ClearRefinements&lt;/code&gt; widget. It allows you to clear all the filters just by clicking on it, instead of having to uncheck them one by one.&lt;/p&gt;

&lt;p&gt;The file should now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { InstantSearch, Highlight, SearchBox, Hits, RefinementList, ClearRefinements } from 'react-instantsearch-dom';
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch';

const searchClient = instantMeiliSearch(
  "http://127.0.0.1:7700",
  ""
);

const App = () =&amp;gt; (
  &amp;lt;InstantSearch
    indexName="Recipe" // Change your index name here
    searchClient={searchClient}
  &amp;gt;
    &amp;lt;div className="left-panel"&amp;gt;
      &amp;lt;ClearRefinements /&amp;gt;
      &amp;lt;h2&amp;gt;Type of diet&amp;lt;/h2&amp;gt;
      &amp;lt;RefinementList attribute="diet" /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div className="right-panel"&amp;gt;
      &amp;lt;SearchBox /&amp;gt;
      &amp;lt;Hits hitComponent={Hit} /&amp;gt;
    &amp;lt;/div&amp;gt;

  &amp;lt;/InstantSearch&amp;gt;
);

const Hit = ({ hit }) =&amp;gt; &amp;lt;Highlight attribute="title" hit={hit} /&amp;gt;

export default App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this to work we need to add some CSS. Let's create a &lt;code&gt;app/assets/stylesheets/recipes.css&lt;/code&gt; file and add the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.right-panel {
    margin-left: 210px;
}

.left-panel {
    float: left;
    width: 200px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just to make it even prettier, let's add some padding and margin to the body and the search bar, and change the font:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* app/assets/stylesheets/recipes.css */

body { 
    font-family: sans-serif; 
    padding: 1em; 
}

.ais-SearchBox { 
    margin: 1em 0; 
}

.right-panel {
    margin-left: 210px;
}

.left-panel {
    float: left;
    width: 200px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ByE212Bk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lh69wqlmrgzd9pf1cf5m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ByE212Bk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lh69wqlmrgzd9pf1cf5m.gif" alt="Typing salad in an styled search bar with type of diet filters on the left, the results are updated as you type" width="880" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And tada! 🎉  You have a nice search bar with a search-as-you-type experience ready! 🥳&lt;/p&gt;

&lt;p&gt;⚠️ Because we used fake data to seed our database, the recipes' &lt;code&gt;title&lt;/code&gt;s, &lt;code&gt;ingredients&lt;/code&gt;, &lt;code&gt;directions&lt;/code&gt;, and &lt;code&gt;diet&lt;/code&gt; type are not necessarily consistent.&lt;br&gt;
Conclusion&lt;/p&gt;

&lt;p&gt;We have learned how to synchronize our Ruby on Rails database with Meilisearch and customize our search settings directly on our Rails app, allowing us to search through our data in milliseconds. To top it all off, we have also created a faceted search interface with a search-as-you-type experience using React.&lt;/p&gt;

&lt;p&gt;We have achieved all this seamlessly, thanks to &lt;a href="https://github.com/meilisearch/meilisearch-rails"&gt;Meilisearch Rails&lt;/a&gt; and &lt;a href="https://github.com/meilisearch/instant-meilisearch"&gt;Instant Meilisearch&lt;/a&gt;. Meilisearch has integrations for almost every popular language or framework. Take a look at the complete list in the &lt;a href="https://github.com/meilisearch/integration-guides/"&gt;Meilisearch integration guides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions, please join us on &lt;a href="https://slack.meilisearch.com/"&gt;Slack&lt;/a&gt;; we are always happy to hear from you. For more information on Meilisearch, check out our &lt;a href="https://github.com/meilisearch/meilisearch/"&gt;Github repository&lt;/a&gt; and &lt;a href="https://docs.meilisearch.com/"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>meilisearch</category>
      <category>react</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to integrate a relevant search into Strapi v4 using Meilisearch</title>
      <dc:creator>Carolina</dc:creator>
      <pubDate>Mon, 13 Jun 2022 16:42:25 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-integrate-a-relevant-search-into-strapi-v4-using-meilisearch-189l</link>
      <guid>https://dev.to/meilisearch/how-to-integrate-a-relevant-search-into-strapi-v4-using-meilisearch-189l</guid>
      <description>&lt;p&gt;This tutorial will show you how to integrate Meilisearch with Strapi v4 to create a search-based web app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing our tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strapi
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://strapi.io/"&gt;Strapi&lt;/a&gt; is a headless CMS. It provides a quick way to create a back-end where we can add and store data. The data is then available through a REST or GraphQL API without having to code anything or configure our database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meilisearch
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/overview.html#what-is-meilisearch"&gt;Meilisearch&lt;/a&gt; is a fast, open-source search engine that's easy to use and deploy. The aim of Meilisearch is to create an out-of-the-box relevant search experience in very few steps, with no configuration needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To be able to follow this tutorial, you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An open &lt;a href="https://www.ionos.com/help/email/troubleshooting-mail-basicmail-business/access-the-command-prompt-or-terminal"&gt;terminal or command prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/download/"&gt;Node.js&lt;/a&gt; &amp;gt;= 12 &amp;lt;= 16&lt;/li&gt;
&lt;li&gt;NPM and NPX (v6 only) (installed with Node.js): package managers that help you access and use JS libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a directory for our app
&lt;/h2&gt;

&lt;p&gt;Let’s create a directory called &lt;code&gt;my-app&lt;/code&gt; where we will add our back and front-end parts of the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a back-end using Strapi
&lt;/h2&gt;

&lt;p&gt;Our first step is to generate a back-end API using Strapi. Go to your open terminal window and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-strapi-app@latest back &lt;span class="nt"&gt;--quickstart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a Strapi app in a new directory called &lt;code&gt;back&lt;/code&gt; and opens the admin dashboard. Create an account or log in so that you have access to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---w4a46Yi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--11.27.18-1.png" class="article-body-image-wrapper"&gt;&lt;img alt="Strapi signup form" src="https://res.cloudinary.com/practicaldev/image/fetch/s---w4a46Yi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--11.27.18-1.png" width="880" height="1243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have created your account, you should be redirected to Strapi's admin dashboard. This is where we will configure our back-end API.&lt;/p&gt;

&lt;p&gt;Our next step is to create a new collection type. A collection is like a blueprint of your content—in this case, it'll be a collection of restaurants. We will create another collection called "Category" to organize our restaurants later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w9I9txAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--11.34.17-2--1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w9I9txAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--11.34.17-2--1.png" alt="Capture-d-e-cran-2022-04-08-a--11.34.17-2--1" width="880" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To follow along, complete the first 4 steps of "Part B: Build your content" from &lt;a href="https://docs.strapi.io/developer-docs/latest/getting-started/quick-start.html"&gt;Strapi's quick start guide&lt;/a&gt;. These will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating collection types&lt;/li&gt;
&lt;li&gt;creating new entries&lt;/li&gt;
&lt;li&gt;setting roles &amp;amp; permissions&lt;/li&gt;
&lt;li&gt;publishing the content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After finishing step 4 of Strapi's quick start guide, two new collections named &lt;code&gt;Restaurant&lt;/code&gt; and &lt;code&gt;Category&lt;/code&gt; should have appeared under &lt;code&gt;Content Manager&lt;/code&gt; &amp;gt; &lt;code&gt;Collection Types&lt;/code&gt;. If we click on &lt;code&gt;Restaurant&lt;/code&gt;, we can see that there is only one. Let's add more by clicking the &lt;code&gt;+ Create new entry&lt;/code&gt; button in the upper-right corner of the dashboard!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8smCQv4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.27.41---copie-1--1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8smCQv4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.27.41---copie-1--1.png" alt="Capture-d-e-cran-2022-04-08-a--18.27.41---copie-1--1" width="880" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll add three restaurants, one by one. For each restaurant, you need to press &lt;code&gt;Save&lt;/code&gt; and then &lt;code&gt;Publish&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;The Butter Biscotte.&lt;/code&gt; Description: &lt;code&gt;All about butter, nothing about health.&lt;/code&gt;
Let’s add the &lt;code&gt;French food&lt;/code&gt; category on the bottom right corner of the page 👇&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pYZVqc7R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.33.44-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pYZVqc7R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.33.44-2.png" alt="Capture-d-e-cran-2022-04-08-a--18.33.44-2" width="880" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Name: &lt;code&gt;The Slimy Snail&lt;/code&gt; Description: &lt;code&gt;Gastronomy is made of garlic and butter.&lt;/code&gt; Category: &lt;code&gt;French food&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name: &lt;code&gt;The Smell of Blue&lt;/code&gt; Description: &lt;code&gt;Blue Cheese is not expired, it is how you eat it. With a bit of butter and a lot of happiness.&lt;/code&gt; Category: &lt;code&gt;French food&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the three restaurants have been added, you should end up with the following page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fyBOVUC4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.42.35-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fyBOVUC4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.42.35-1.png" alt="Capture-d-e-cran-2022-04-08-a--18.42.35-1" width="880" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our Strapi back-end is now up and running! Strapi automatically creates a REST API for our &lt;code&gt;Restaurants&lt;/code&gt; collection. Check out Strapi's documentation for all available &lt;a href="https://strapi.io/documentation/developer-docs/latest/developer-resources/content-api/content-api.html#api-endpoints"&gt;API endpoints&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, it's time to bring Meilisearch into the mix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launch and start Meilisearch
&lt;/h2&gt;

&lt;p&gt;There are multiple ways to &lt;a href="https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch"&gt;download and run a Meilisearch instance&lt;/a&gt;, we will be using &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; here.&lt;/p&gt;

&lt;p&gt;Want to avoid a local installation? To quickly create a best-in-class search experience, we offer the convenience of &lt;a href="https://cloud.meilisearch.com/"&gt;Meilisearch Cloud&lt;/a&gt;, a hosted and fully‑managed version of Meilisearch. If you would like to try it, you can still &lt;a href="https://meilisearch.typeform.com/to/FtnzvZfh?typeform-source=www.meilisearch.com"&gt;register on the waiting list&lt;/a&gt; or wait for the public release planned a few weeks from now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open a second terminal window&lt;/strong&gt; and move to the &lt;code&gt;my-app&lt;/code&gt; directory. This window will be used to run Meilisearch. Execute the command below to download and install Meilisearch with Docker. If Docker doesn't work for you, consider trying one of the &lt;a href="https://docs.meilisearch.com/learn/getting_started/installation.html#download-and-launch"&gt;many other methods&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fetch the latest version of Meilisearch image from DockerHub&lt;/span&gt;
docker pull getmeili/meilisearch:latest

&lt;span class="c"&gt;# Launch Meilisearch&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-p&lt;/span&gt; 7700:7700 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data.ms:/data.ms &lt;span class="se"&gt;\&lt;/span&gt;
    getmeili/meilisearch:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a big chunk of text (including some ASCII art) confirming that Meilisearch is up and running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uUuEohIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.44.16-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uUuEohIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.44.16-1.png" alt="Capture-d-e-cran-2022-04-08-a--18.44.16-1" width="880" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find the line titled &lt;code&gt;Server listening on&lt;/code&gt;. This lets us know where Meilisearch is being served. Once you've found it, open this address in your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9pdic7TI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.47.49-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9pdic7TI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--18.47.49-1.png" alt="Capture-d-e-cran-2022-04-08-a--18.47.49-1" width="880" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the Meilisearch &lt;a href="https://docs.meilisearch.com/learn/what_is_meilisearch/search_preview.html"&gt;search preview&lt;/a&gt;. It will remain empty until we add some data to our Meilisearch instance.&lt;/p&gt;

&lt;p&gt;It’s time to connect Strapi and Meilisearch and start searching through our data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect Strapi and Meilisearch
&lt;/h2&gt;

&lt;p&gt;In order to add the Meilisearch plugin to Strapi, we need to quit our Strapi app. Go to the terminal window running Strapi (&lt;em&gt;make sure it's not the one running Meilisearch!&lt;/em&gt;) and push &lt;code&gt;Ctrl+C&lt;/code&gt; to kill the process.&lt;/p&gt;

&lt;p&gt;Once you've done that, install the plugin in the &lt;code&gt;back&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd back
npm install strapi-plugin-meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the installation, we have to rebuild our Strapi app before starting it again in development mode, since it makes configuration easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
npm run develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, our Strapi app should be running once again on the default address: &lt;a href="http://localhost:1337/admin/"&gt;http://localhost:1337/admin/&lt;/a&gt;. Visiting it in your browser, you should see an admin sign-in page; enter the same credentials as before.&lt;/p&gt;

&lt;p&gt;Once connected, you should see the new &lt;code&gt;meilisearch&lt;/code&gt; plugin on the left side of the screen. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9oN7ID5V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--19.01.53-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9oN7ID5V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--19.01.53-1.png" alt="Capture-d-e-cran-2022-04-08-a--19.01.53-1" width="880" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add your Meilisearch credentials, click on the &lt;code&gt;Settings&lt;/code&gt; tab on the meilisearch plugin page so that Strapi knows where to send our data.&lt;/p&gt;

&lt;p&gt;For example, using the credentials from the &lt;strong&gt;Launch and start Meilisearch&lt;/strong&gt; section above, add the address serving Meilisearch in the &lt;code&gt;Meilisearch Host&lt;/code&gt; field, then click the &lt;code&gt;Save&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zIQljtP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--19.06.13-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zIQljtP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/Capture-d-e-cran-2022-04-08-a--19.06.13-1.png" alt="Capture-d-e-cran-2022-04-08-a--19.06.13-1" width="880" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that we leave &lt;code&gt;Meilisearch API Key&lt;/code&gt; blank because we launched Meilisearch without a &lt;a href="https://docs.meilisearch.com/reference/features/configuration.html#master-key"&gt;master key&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now it's time to add your Strapi collection to Meilisearch. In the &lt;code&gt;Collections&lt;/code&gt; tab on the &lt;code&gt;meilisearch&lt;/code&gt; plugin page, you should see the &lt;code&gt;restaurant&lt;/code&gt; and &lt;code&gt;category&lt;/code&gt; content-types.&lt;/p&gt;

&lt;p&gt;By clicking on the checkbox next to &lt;code&gt;restaurant&lt;/code&gt;, the content-type is automatically indexed in Meilisearch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZtbEdIi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/strapi-gif.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ZtbEdIi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/strapi-gif.gif" alt="strapi-gif" width="880" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the GIF above, the word “Hooked” appears when you click on the restaurant's checkbox in the &lt;code&gt;Collections&lt;/code&gt; tab. This means that each time you add, update or delete an entry in your restaurant content-types, Meilisearch is automatically updated!&lt;/p&gt;

&lt;p&gt;Once the indexing finishes, your restaurants are in Meilisearch. We can now go back to our Meilisearch host address: &lt;a href="http://127.0.0.1:7700"&gt;http://127.0.0.1:7700&lt;/a&gt;. After refreshing, you should observe that the page is no longer empty. Try typing “butter” in the search bar and see what happens 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SBWJlcJJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/butter-gif.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SBWJlcJJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.meilisearch.com/content/images/2022/04/butter-gif.gif" alt="butter-gif" width="880" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, your Strapi entries are sent to Meilisearch as is. You can modify the data before sending it to Meilisearch, for instance by removing a field. Check out all the customization options on the &lt;a href="https://github.com/meilisearch/strapi-plugin-meilisearch/#customisation"&gt;strapi-plugin-meilisearch&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Now that you have your Strapi collections in Meilisearch, you can &lt;a href="https://docs.meilisearch.com/reference/api/search.html"&gt;start searching&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Learn how to &lt;a href="https://blog.meilisearch.com/instant-meilisearch/"&gt;set up instant-meilisearch&lt;/a&gt; to integrate a search-as-you-type experience into your front end in no time at all!&lt;/p&gt;

&lt;p&gt;If you have any questions, please join us on &lt;a href="https://meilicommunity.slack.com/"&gt;Slack&lt;/a&gt;. If you like Meilisearch, &lt;a href="https://github.com/meilisearch/meilisearch"&gt;a star on GitHub&lt;/a&gt; means a lot.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>meilisearch</category>
      <category>strapi</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to use HTTP/2 and SSL with MeiliSearch</title>
      <dc:creator>Quentin de Quelen</dc:creator>
      <pubDate>Thu, 24 Sep 2020 12:06:11 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-use-http-2-and-ssl-with-meilisearch-h4p</link>
      <guid>https://dev.to/meilisearch/how-to-use-http-2-and-ssl-with-meilisearch-h4p</guid>
      <description>&lt;p&gt;For those willing to use HTTP/2, please be aware that it is &lt;strong&gt;only possible if your server is configured with SSL certificate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Therefore, you will see how to launch a MeiliSearch server with SSL. This tutorial gives a short introduction to do it locally, but you can as well do the same thing on a remote server.&lt;/p&gt;

&lt;p&gt;First of all, you need the &lt;a href="https://docs.meilisearch.com/reference/features/installation.html"&gt;binary of MeiliSearch&lt;/a&gt;, or you can also use docker. In the latter case, it is necessary to pass the parameters using environment variables and the SSL certificates via a volume.&lt;/p&gt;

&lt;p&gt;A tool to generate SSL certificates is also required. In this How To, you will use &lt;a href="https://github.com/FiloSottile/mkcert"&gt;mkcert&lt;/a&gt;. However, if on a remote server, you can also use certbot or certificates signed by a Certificate Authority.&lt;/p&gt;

&lt;p&gt;Then, use &lt;code&gt;curl&lt;/code&gt; to do requests. It is a simple way to specify that you want to send HTTP/2 requests by using the &lt;code&gt;--http2&lt;/code&gt; option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to use HTTP/2 without SSL
&lt;/h2&gt;

&lt;p&gt;Start by running the binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, send a request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -kvs --http2 --request GET 'http://localhost:7700/indexes'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will get the following answer from the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 7700 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 7700 (#0)
&amp;gt; GET /indexes HTTP/1.1
&amp;gt; Host: localhost:7700
&amp;gt; User-Agent: curl/7.64.1
&amp;gt; Accept: */*
&amp;gt; Connection: Upgrade, HTTP2-Settings
&amp;gt; Upgrade: h2c
&amp;gt; HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
&amp;gt;
&amp;lt; HTTP/1.1 200 OK
&amp;lt; content-length: 2
&amp;lt; content-type: application/json
&amp;lt; date: Fri, 17 Jul 2020 11:01:02 GMT
&amp;lt;
* Connection #0 to host localhost left intact
[]* Closing connection 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see on line &lt;code&gt;&amp;gt; Connection: Upgrade, HTTP2-Settings&lt;/code&gt; that the server tries to upgrade to HTTP/2, but is unsuccessful.&lt;br&gt;
The answer &lt;code&gt;&amp;lt; HTTP/1.1 200 OK&lt;/code&gt; indicates that the server still uses HTTP/1.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try to use HTTP/2 with SSL
&lt;/h2&gt;

&lt;p&gt;This time, start by generating the SSL certificates. mkcert creates two files: &lt;code&gt;127.0.0.1.pem&lt;/code&gt; and &lt;code&gt;127.0.0.1-key.pem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkcert '127.0.0.1'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, use the certificate and the key to configure MeiliSearch with SSL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./meilisearch --ssl-cert-path ./127.0.0.1.pem --ssl-key-path ./127.0.0.1-key.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, make the same request as above but change &lt;code&gt;http://&lt;/code&gt; to &lt;code&gt;https://&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -kvs --http2 --request GET 'https://localhost:7700/indexes'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will get the following answer from the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 7700 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 7700 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: O=mkcert development certificate; OU=quentindequelen@s-iMac (Quentin de Quelen)
*  start date: Jun  1 00:00:00 2019 GMT
*  expire date: Jul 17 10:38:53 2030 GMT
*  issuer: O=mkcert development CA; OU=quentindequelen@s-iMac (Quentin de Quelen); CN=mkcert quentindequelen@s-iMac (Quentin de Quelen)
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7ff601009200)
&amp;gt; GET /indexes HTTP/2
&amp;gt; Host: localhost:7700
&amp;gt; User-Agent: curl/7.64.1
&amp;gt; Accept: */*
&amp;gt;
* Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)!
&amp;lt; HTTP/2 200
&amp;lt; content-length: 2
&amp;lt; content-type: application/json
&amp;lt; date: Fri, 17 Jul 2020 11:06:27 GMT
&amp;lt;
* Connection #0 to host localhost left intact
[]* Closing connection 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the server now supports HTTP/2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server successfully receives HTTP/2 requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt; HTTP/2 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>meilisearch</category>
      <category>certbot</category>
      <category>ssl</category>
      <category>mkcert</category>
    </item>
    <item>
      <title>Integrate a relevant search bar to your documentation with MeiliSearch</title>
      <dc:creator>curquiza</dc:creator>
      <pubDate>Thu, 24 Sep 2020 10:47:33 +0000</pubDate>
      <link>https://dev.to/meilisearch/integrate-a-relevant-search-bar-to-your-documentation-3nl9</link>
      <guid>https://dev.to/meilisearch/integrate-a-relevant-search-bar-to-your-documentation-3nl9</guid>
      <description>&lt;p&gt;You might have noticed the search bar in &lt;a href="https://docs.meilisearch.com/"&gt;our documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fowunn6mzq1j6j8b1jm3z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fowunn6mzq1j6j8b1jm3z.gif" alt="Alt Text" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you are probably wanting the same for your own documentation!&lt;/p&gt;

&lt;p&gt;This tutorial will guide you through the steps of building a relevant and powerful search bar for your documentation 🚀&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run a MeiliSearch instance&lt;/li&gt;
&lt;li&gt;Scrape your content&lt;/li&gt;
&lt;li&gt;Integrate the search Bar&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Run a MeiliSearch Instance
&lt;/h1&gt;

&lt;p&gt;First of all, you need your documentation content to be scraped and pushed into a MeiliSearch instance.&lt;/p&gt;

&lt;p&gt;You can install and run MeiliSearch on your machine using &lt;code&gt;curl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://install.meilisearch.com | sh
&lt;span class="nv"&gt;$ &lt;/span&gt;./meilisearch &lt;span class="nt"&gt;--master-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;myMasterKey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are &lt;a href="https://docs.meilisearch.com/reference/features/installation.html#download-and-launch"&gt;other ways to install MeiliSearch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;MeiliSearch is open-source and can run either on your server or on any cloud provider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The host URL and the API key you will provide in the next steps correspond to the credentials of this MeiliSearch instance.&lt;br&gt;
In the example above, the host URL is &lt;code&gt;http://localhost:7700&lt;/code&gt; and the API key is &lt;code&gt;myMasterKey&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Scrape your Content
&lt;/h1&gt;

&lt;p&gt;The Meili team provides and maintains a &lt;a href="https://github.com/meilisearch/docs-scraper"&gt;scraper tool&lt;/a&gt; to automatically read the content of your website and store it into an index in MeiliSearch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration File
&lt;/h2&gt;

&lt;p&gt;The scraper tool needs a configuration file to know what content you want to scrape. This is done by providing selectors (e.g. the HTML tag).&lt;/p&gt;

&lt;p&gt;Here is an example of a basic configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"index_uid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://www.example.com/doc/"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sitemap_urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://www.example.com/sitemap.xml"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stop_urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"selectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl0"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-lvl0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"global"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Documentation"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-lvl1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"global"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"default_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Chapter"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content .docs-lvl2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl3"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content .docs-lvl3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl4"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content .docs-lvl4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl5"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content .docs-lvl5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lvl6"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content .docs-lvl6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".docs-content p, .docs-content li"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;index_uid field&lt;/code&gt; is the index identifier in your MeiliSearch instance in which your website content is stored. The scraping tool will create a new index if it does not exist.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;docs-content&lt;/code&gt; class is the main container of the textual content in this example. Most of the time, this tag is a &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; or an &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; HTML element.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lvlX&lt;/code&gt; selectors should use the standard title tags like &lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt;, &lt;code&gt;h3&lt;/code&gt;, etc. You can also use static classes. Set a unique &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;name&lt;/code&gt; attribute to these elements.&lt;/p&gt;

&lt;p&gt;Every searchable &lt;code&gt;lvl&lt;/code&gt; elements outside this main documentation container (for instance, in a sidebar) must be &lt;code&gt;global&lt;/code&gt; selectors. They will be globally picked up and injected to every document built from your page.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TIP: More &lt;a href="https://github.com/meilisearch/docs-scraper#all-the-config-file-settings"&gt;optional fields are available&lt;/a&gt; to fit your need.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use VuePress for your documentation, you can check out the &lt;a href="https://github.com/meilisearch/documentation/blob/master/.vuepress/docs-scraper/docs-scraper.config.json"&gt;configuration file&lt;/a&gt; we use in production.&lt;br&gt;
In our case, the main container is &lt;code&gt;theme-default-content&lt;/code&gt; and the selector the titles and sub-titles are &lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt;...&lt;/p&gt;
&lt;h2&gt;
  
  
  Run the Scraper
&lt;/h2&gt;

&lt;p&gt;You can run the scraper with Docker. With our local MeiliSearch instance set up at the first step, we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--network&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MEILISEARCH_HOST_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'http://localhost:7700'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MEILISEARCH_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'myMasterKey'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &amp;lt;absolute-path-to-your-config-file&amp;gt;:/docs-scraper/config.json &lt;span class="se"&gt;\&lt;/span&gt;
    getmeili/docs-scraper:latest pipenv run ./docs_scraper config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you don't want to use Docker, here are &lt;a href="https://github.com/meilisearch/docs-scraper#run-the-scraper"&gt;other ways to run the scraper&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;absolute-path-to-your-config-file&amp;gt;&lt;/code&gt; should be the &lt;strong&gt;absolute&lt;/strong&gt; path of your configuration file defined at the previous step.&lt;/p&gt;

&lt;p&gt;The API key you must provide should have the permissions to add documents into your MeiliSearch instance. In a production environment, we recommend providing the private key instead of the master key, as it is safer and it has enough permissions to perform such requests.&lt;br&gt;
&lt;em&gt;More about &lt;a href="https://docs.meilisearch.com/reference/features/authentication.html"&gt;MeiliSearch authentication&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TIP: We recommend running the scraper at each new deployment of your documentation, &lt;a href="https://github.com/meilisearch/documentation/blob/master/.github/workflows/gh-pages-scraping.yml"&gt;as we do for the MeiliSearch's one&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Integrate the Search Bar
&lt;/h1&gt;

&lt;p&gt;If your documentation is not a VuePress application, you can directly go to this section.&lt;/p&gt;
&lt;h3&gt;
  
  
  For a VuePress Documentation
&lt;/h3&gt;

&lt;p&gt;If you use VuePress for your documentation, we provide a &lt;a href="https://github.com/meilisearch/vuepress-plugin-meilisearch"&gt;VuePress plugin&lt;/a&gt;. This plugin is used in production in the MeiliSearch documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuk301fod1i5anz76ydv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuk301fod1i5anz76ydv5.png" alt="Alt Text" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your VuePress project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add vuepress-plugin-meilisearch
&lt;span class="c"&gt;# or&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;vuepress-plugin-meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;config.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vuepress-plugin-meilisearch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hostUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-meilisearch-host-url&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiKey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;your-meilisearch-api-key&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;indexUid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;hostUrl&lt;/code&gt; and the &lt;code&gt;apiKey&lt;/code&gt; fields are the credentials of the MeiliSearch instance. Following on from this tutorial, they are respectively &lt;code&gt;http://localhost:7700&lt;/code&gt; and &lt;code&gt;myMasterKey&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;indexUid&lt;/code&gt; is the index identifier in your MeiliSearch instance in which your website content is stored. It has been defined in the config file.&lt;/p&gt;

&lt;p&gt;These three fields are mandatory, but more &lt;a href="https://github.com/meilisearch/vuepress-plugin-meilisearch#customization"&gt;optional fields are available&lt;/a&gt; to customize your search bar.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: Since the configuration file is public, we strongly recommend providing the MeiliSearch public key in a production environment, which is enough to perform search requests.&lt;br&gt;
Read more about &lt;a href="https://docs.meilisearch.com/reference/features/authentication.html"&gt;MeiliSearch authentication&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  For All Kinds of Documentation
&lt;/h3&gt;

&lt;p&gt;If you don't use VuePress for your documentation, we provide a &lt;a href="https://github.com/meilisearch/docs-searchbar.js"&gt;front-end SDK&lt;/a&gt; to integrate a powerful and relevant search bar to any documentation website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhtzyf8heq1k1w3a3bgih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhtzyf8heq1k1w3a3bgih.png" alt="Alt Text" width="800" height="558"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/docs-searchbar.js@{version}/dist/cdn/docs-searchbar.min.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"search-bar-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/docs-searchbar.js@{version}/dist/cdn/docs-searchbar.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;docsSearchBar&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;hostUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;your-meilisearch-host-url&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;your-meilisearch-api-key&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;indexUid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;inputSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search-bar-input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// Set debug to true if you want to inspect the dropdown&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;hostUrl&lt;/code&gt; and the &lt;code&gt;apiKey&lt;/code&gt; fields are the credentials of the MeiliSearch instance. Following on from this tutorial, they are respectively &lt;code&gt;http://localhost:7700&lt;/code&gt; and &lt;code&gt;myMasterKey&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;indexUid&lt;/code&gt; is the index identifier in your MeiliSearch instance in which your website content is stored. It has been defined in the config file.&lt;br&gt;
&lt;code&gt;inputSelector&lt;/code&gt; is the &lt;code&gt;id&lt;/code&gt; attribute of the HTML search input tag.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: We strongly recommend providing the MeiliSearch public key in a production environment, which is enough to perform search requests.&lt;br&gt;
Read more about &lt;a href="https://docs.meilisearch.com/reference/features/authentication.html"&gt;MeiliSearch authentication&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The default behavior of this library fits perfectly for a documentation search bar, but you might need &lt;a href="https://github.com/meilisearch/docs-searchbar.js#customization"&gt;some customizations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more concrete examples, you can check out this &lt;a href="https://github.com/meilisearch/docs-searchbar.js/blob/master/scripts/playground.html"&gt;basic HTML file&lt;/a&gt; or &lt;a href="https://github.com/meilisearch/vuepress-plugin-meilisearch/blob/master/MeiliSearchBox.vue"&gt;this more advanced Vue file&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's next?
&lt;/h1&gt;

&lt;p&gt;At this point you should have a working search engine on your website, congrats! 🎉&lt;br&gt;
You can check &lt;a href="https://docs.meilisearch.com/running-production/"&gt;this tutorial&lt;/a&gt; if you now want to run MeiliSearch in production!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to implement Meilisearch in your React App</title>
      <dc:creator>cvermand</dc:creator>
      <pubDate>Thu, 24 Sep 2020 09:12:05 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-implement-meilisearch-in-your-react-app-1m5e</link>
      <guid>https://dev.to/meilisearch/how-to-implement-meilisearch-in-your-react-app-1m5e</guid>
      <description>&lt;p&gt;&lt;em&gt;The following is a guest post by Riccardo Giorato.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecatlon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecatlon.png" alt="Decathlon front page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this quick tutorial, you'll learn how to easily create a search page with instant and reliable results thanks to the power of &lt;strong&gt;MeiliSearch&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MeiliSearch is an open source, high-relevancy search engine, built in &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will cover the basic steps to get the search running and move on to more advanced topics at the end.&lt;/p&gt;

&lt;p&gt;For the example, let's recreate a fast and beautiful search experience for a Sport brand.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://www.youtube.com/embed/PA5LI1xldMA" rel="noopener noreferrer"&gt;&lt;strong&gt;video preview&lt;/strong&gt;&lt;/a&gt; of what you will be building:&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before getting started, ensure that you have &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node&lt;/a&gt; already installed on your machine.&lt;/p&gt;

&lt;p&gt;You will create the boilerplate code for your React app using the custom project we created for you : &lt;a href="https://github.com/Giorat/meili_react_demo" rel="noopener noreferrer"&gt;https://github.com/Giorat/meili_react_demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, this tutorial assumes that you are already familiar with &lt;a href="https://reactjs.org/docs/getting-started.html" rel="noopener noreferrer"&gt;React&lt;/a&gt;. If that is not the case, you can check the React Documentation to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clone the Repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Giorat/meili_react_demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;meili_react_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run a new Docker image
&lt;/h3&gt;

&lt;p&gt;If you cloned the repository, to set up the MeiliSearch instance just execute inside the main folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run setup_meili
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you didn't clone the repo and you want to create directly the Docker instance execute this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 7700:7700 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data.ms:/data.ms getmeili/meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be able to check that MeiliSearch is running by visiting the following URL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://localhost:7700/" rel="noopener noreferrer"&gt;http://localhost:7700/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create an Index in MeiliSearch
&lt;/h2&gt;

&lt;p&gt;An index is an entity in which documents are stored, like an array of objects with some specific settings attached to it and a unique primary key.&lt;/p&gt;

&lt;p&gt;You can read more about the properties of &lt;a href="https://docs.meilisearch.com/learn/core_concepts/indexes.html" rel="noopener noreferrer"&gt;indexes&lt;/a&gt; in the the MeiliSearch documentation.&lt;/p&gt;

&lt;p&gt;In order to create your index, you need to find out what your primary key is. Below is a sample document to add to MeiliSearch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100013768717&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fitness Foldable Shoe Bag"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.decathlon.com/products/gym-foldable-shoe-bag"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vendor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Domyos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sport bag"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Artistic Gymnastics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Boy's"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"CARDIO_FITNESS_ACCESSORIES"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"CARDIO_FITNESS_BAGS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"CODE_R3: 11782"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://cdn.shopify.com/s/files/1/1330/6287/products/sac_20a_20chaussure_20kaki_20_7C_20001_20_7C_20PSHOT_20_490180e6-44e4-4340-8e3d-c29eb70c6ac8.jpg?v=1584683232"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"creation_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-04-03T15:58:48-07:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.49"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this document, the field that holds the unique value of the document is the &lt;code&gt;id&lt;/code&gt; field. This attribute is called the &lt;code&gt;primary key&lt;/code&gt; in MeiliSearch.&lt;/p&gt;

&lt;p&gt;You can easily create this Index with a Rest client like Postman but, in this tutorial, you will use the MeiliSearch Javascript SDK to do it directly from node.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MeiliSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meilisearch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:7700&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MeiliSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decathlon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Meili error: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Index documents
&lt;/h2&gt;

&lt;p&gt;MeiliSearch receives documents in JSON format and stores them for searching purposes. These documents are composed of fields that can hold any type of data.&lt;/p&gt;

&lt;p&gt;For this tutorial, you can download this dataset full of sportswear items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Giorat/meili_react_demo/blob/master/backend/decathlon.json" rel="noopener noreferrer"&gt;decathlon.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To upload all the objects from this JSON file, use the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MeiliSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meilisearch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:7700&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MeiliSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decathlon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./decathlon.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// path to json file&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decathlon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decathlon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Meili error: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to change the path to your JSON file before running this script!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the React App
&lt;/h2&gt;

&lt;p&gt;You will use a standard React App that you can create using CRA or simply by cloning this repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Giorat/meili_react_demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;meili_react_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you prefer to start from an empty app you can create your own using the following command. You can name the application however you desire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app meili_react_demo
&lt;span class="nb"&gt;cd &lt;/span&gt;meili_react_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Including Tailwind CSS
&lt;/h3&gt;

&lt;p&gt;To speed up the styling process, add Tailwind CSS style directly to index.html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure App.js State
&lt;/h3&gt;

&lt;p&gt;Then, modify the App.js file using this code to set up a simple Search form and a few State variables to handle every aspect of the search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// TODO configure the MeiliSearch Client&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchedWord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dumbell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resultSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resultCards&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCards&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="c1"&gt;// TODO add function to send searchedWord to MeiliSearch&lt;/span&gt;

  &lt;span class="c1"&gt;// TODO add function to parse the JSON object&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mx-auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header font-sans text-white items-center justify-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;py-12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-20 w-auto items-center justify-center p-2 mx-auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/wide_logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invert(0%)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-wrap flex-grow text-3xl w-full justify-center p-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Stop&lt;/span&gt; &lt;span class="nx"&gt;looking&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;find&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;work&lt;/span&gt; &lt;span class="nx"&gt;hard&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border rounded overflow-hidden w-full flex justify-center mx-auto searchBox mt-6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex items-center justify-center px-4 shadow-md bg-white text-black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;svg&lt;/span&gt;
                &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-4 w-4 text-grey-dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;currentColor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;xmlns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://www.w3.org/2000/svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="nx"&gt;viewBox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 0 24 24&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;M16.32 14.9l5.39 5.4a1 1 0 0 1-1.42 1.4l-5.38-5.38a8 8 0 1 1 1.41-1.41zM10 16a6 6 0 1 0 0-12 6 6 0 0 0 0 12z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/svg&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
              &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchedWord&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
              &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px-6 py-4 w-full text-black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Product, sport, color, …&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-wrap searchResults&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;resultCards&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code should output this beautiful header with a search form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecat_before.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecat_before.png" alt="Decathlon front page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Search Results in React
&lt;/h2&gt;

&lt;p&gt;Connecting to MeiliSearch from React using the MeiliSearch Javascript SDK is a simple operation that can be done in just a few steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  MeiliSearch Client
&lt;/h3&gt;

&lt;p&gt;Install the MeiliSearch SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# if you use npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;meilisearch
&lt;span class="c"&gt;# if you use yarn&lt;/span&gt;
yarn add meilisearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up the MeiliSearch Client with the server URL. In our case, it was the localhost Docker machine. Finally, load the right Index from the backend.&lt;/p&gt;

&lt;p&gt;Replace this comment in App.js by the code snippet below:&lt;br&gt;
&lt;code&gt;// TODO configure the MeiliSearch Client&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MeiliSearch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meilisearch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MeiliSearch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://127.0.0.1:7700/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decathlon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send the Search Query
&lt;/h3&gt;

&lt;p&gt;Use an &lt;code&gt;useEffect&lt;/code&gt; to execute the search of the typed words into MeiliSearch. All the results hits will be set to a simple state variable called “resultsSearch”.&lt;/p&gt;

&lt;p&gt;Replace this comment in App.js by the code snippet below:&lt;br&gt;
&lt;code&gt;// TODO add function to send searchedWord to MeiliSearch&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create an scoped async function in the hook&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchWithMeili&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchedWord&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Execute the created function directly&lt;/span&gt;
    &lt;span class="nf"&gt;searchWithMeili&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchedWord&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Showcase the Results
&lt;/h3&gt;

&lt;p&gt;Inside a second &lt;code&gt;useEffect&lt;/code&gt;, you will search through the JSON objects returned by MeiliSearch. They will have the same structure than the uploaded JSON objects.&lt;/p&gt;

&lt;p&gt;Then, it's time to create a list of cards linking to the products pages.&lt;/p&gt;

&lt;p&gt;Replace this comment in App.js by the code snippet below:&lt;br&gt;
&lt;code&gt;// TODO add function to parse the JSON object&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;arrayItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;resultSearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resultSearch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;arrayItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex w-full sm:w-1/2 md:w-1/3 lg:w-1/4 xl:w-1/6 p-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
            &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex-1 rounded overflow-hidden shadow-lg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
              &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w-full h-48 object-cover&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/wide_logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
            &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px-6 py-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-bold text-sm mb-1 text-gray-600 capitalize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-bold text-xl mb-2 text-gray-800&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vendor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-black text-xl font-bold text-base py-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setCards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayItems&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resultSearch&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can have a look at the full &lt;a href="https://github.com/Giorat/meili_react_demo/blob/master/src/App.js" rel="noopener noreferrer"&gt;App.js&lt;/a&gt; code here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Giorat/meili_react_demo/blob/master/src/App.js" rel="noopener noreferrer"&gt;https://github.com/Giorat/meili_react_demo/blob/master/src/App.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can visit the live application here: &lt;a href="https://meili-react-demo.netlify.app/" rel="noopener noreferrer"&gt;https://meili-react-demo.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecatlon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdocs.meilisearch.com%2Freact-guide%2Fdecatlon.png" alt="Decathlon front page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Search even more!
&lt;/h2&gt;

&lt;p&gt;With MeiliSearch, you get a ton of other small options you can fine-tune to improve your Search experience. For advanced exploration, you will need to do a few extra configuration steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Ranking
&lt;/h3&gt;

&lt;p&gt;Start by changing the search rankings, or more simply, the way MeiliSearch looks through the documents you uploaded to find the references to your search terms inside the &lt;a href="///guides/main_concepts/relevancy.md#relevancy"&gt;rankingRules&lt;/a&gt; object. In that case, set the following ranking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"typo"&lt;/li&gt;
&lt;li&gt;"words"&lt;/li&gt;
&lt;li&gt;"proximity"&lt;/li&gt;
&lt;li&gt;"attribute"&lt;/li&gt;
&lt;li&gt;"wordsPosition"&lt;/li&gt;
&lt;li&gt;"exactness"&lt;/li&gt;
&lt;li&gt;"desc(creation_date)"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration is the default one except for the last field which is a custom rule "desc(creation_date)". The latter ranks items by their creation date if all previous values are identical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Searchable Attributes
&lt;/h3&gt;

&lt;p&gt;Secondly, you have to specify the attributes that MeiliSearch can search from in each document, inside a &lt;a href="///guides/advanced_guides/field_properties.md#searchable-fields"&gt;searchableAttributes&lt;/a&gt; object. Here, the configuration is done to search only on name, vendor, category and tags leaving out images or URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Displayed Attributes
&lt;/h3&gt;

&lt;p&gt;Lastly, you have to specify the attributes that MeiliSearch can return to the user by the Frontend application with the &lt;a href="http://localhost:8080/guides/advanced_guides/field_properties.md#displayed-fields" rel="noopener noreferrer"&gt;displayedAttributes&lt;/a&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload the new Settings to MeiliSearch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MeiliSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meilisearch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:7700&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MeiliSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;meili&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decathlon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;rankingRules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;words&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proximity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attribute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wordsPosition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exactness&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;desc(creation_date)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;searchableAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;displayedAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;images&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newSettings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Meili error: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This quick search wouldn’t be possible without an incredible team that is working on this great project night and day! If you might enjoy contributing to the MeiliSearch family you can jump on these repositories to bring some help, issues or tips and tricks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/meilisearch/MeiliSearch" rel="noopener noreferrer"&gt;https://github.com/meilisearch/MeiliSearch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/meilisearch/meilisearch-js" rel="noopener noreferrer"&gt;https://github.com/meilisearch/meilisearch-js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;General discussion is very welcome on the forum or chat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/meilisearch/MeiliSearch/discussions" rel="noopener noreferrer"&gt;https://github.com/meilisearch/MeiliSearch/discussions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.meilisearch.com/" rel="noopener noreferrer"&gt;https://slack.meilisearch.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And also don’t forget to leave a Star on the main project on &lt;a href="https://github.com/meilisearch/MeiliSearch" rel="noopener noreferrer"&gt;Github here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>search</category>
      <category>react</category>
    </item>
    <item>
      <title>How to deploy a MeiliSearch instance on DigitalOcean</title>
      <dc:creator>Samuel Jimenez</dc:creator>
      <pubDate>Wed, 23 Sep 2020 13:50:38 +0000</pubDate>
      <link>https://dev.to/meilisearch/how-to-deploy-a-meilisearch-instance-on-digitalocean-139h</link>
      <guid>https://dev.to/meilisearch/how-to-deploy-a-meilisearch-instance-on-digitalocean-139h</guid>
      <description>&lt;h1&gt;
  
  
  How to deploy a MeiliSearch instance on DigitalOcean
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Create an out-of-the-box MeiliSearch
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a new "droplet"
&lt;/h3&gt;

&lt;p&gt;A "droplet" is a set of resources, as a Virtual Machine, or a Server, in which you can run your own applications.&lt;br&gt;
In any DigitalOcean page, when you are logged in, you will find a menu in the upper-right corner. Click on "Create" -&amp;gt; "Droplets".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NxHZOySd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/01.create.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NxHZOySd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/01.create.png" alt="Create droplet" width="331" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Select MeiliSearch snapshot
&lt;/h3&gt;

&lt;p&gt;By default, DigitalOcean will display the "distributions" tab. Select the "Marketplace" tab and search for "meili". Select it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f7W48Ocn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/02.marketplace.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f7W48Ocn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/02.marketplace.png" alt="Marketplace" width="880" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Select your plan
&lt;/h3&gt;

&lt;p&gt;Select your plan. Plans start at $5 (click on "See all plans" for more options). Memory-optimized options will give you better results for a production environment on big datasets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tT_rBWJM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/03.select-plan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tT_rBWJM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/03.select-plan.png" alt="Select plan" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Select a region for your droplet
&lt;/h3&gt;

&lt;p&gt;Select the region where you want to deploy your droplet. Remember, the closer you are to your users or customers, the better will be their search experience with MeiliSearch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8W6CJiku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/04.select-region.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8W6CJiku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/04.select-region.png" alt="Select region" width="880" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Add your ssh key
&lt;/h3&gt;

&lt;p&gt;Select your SSH key in order to be able to connect to your droplet later. If you don't see your SSH key add yours to your account.&lt;/p&gt;

&lt;p&gt;If you need help with this, visit &lt;a href="https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/"&gt;this link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also set a password for &lt;code&gt;root&lt;/code&gt; user if you prefer this authentication method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tE1GnNWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/05.add-ssh-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tE1GnNWx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/05.add-ssh-key.png" alt="Add ssh key" width="880" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Choose your droplet name and tags
&lt;/h3&gt;

&lt;p&gt;Here you can select the name that will be visible everywhere in your DigitalOcean account. Choose wisely!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dZCPjYmD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/06.droplet-name.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dZCPjYmD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/06.droplet-name.png" alt="Droplet name" width="880" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tags are a very good method to know who created resources, and for organizing resources or projects. Try to always add some tags to make clear what are the server purposes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lFC9_R1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/06.add-tags.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lFC9_R1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/06.add-tags.png" alt="Add tags" width="880" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Finally click on Create Droplet
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6hC7rEGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/07.create-droplet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6hC7rEGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/07.create-droplet.png" alt="Create droplet" width="880" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Your MeiliSearch is running (with no config)
&lt;/h3&gt;

&lt;p&gt;Instance creation in progress...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Tm2G11W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/08.creating.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Tm2G11W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/08.creating.png" alt="Creating" width="880" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pOJyaWhh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/08.created-ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pOJyaWhh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/08.created-ip.png" alt="Created" width="880" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Test MeiliSearch.
&lt;/h3&gt;

&lt;p&gt;Copy the public IP address:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--54c-STWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/09.copy-ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--54c-STWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/09.copy-ip.png" alt="Copy IP" width="880" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste it in your browser. If this screen is shown, your MeiliSearch is now ready!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OaBXjVS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/09.test-meili.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OaBXjVS9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/09.test-meili.png" alt="Test MeiliSearch" width="880" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure production settings in your MeiliSearch Droplet
&lt;/h2&gt;

&lt;p&gt;Configuring your MeiliSearch from a DigitalOcean droplet is very straightforward. Establish an SSH connection with your droplet and a script will guide you through the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Make your domain name point to your droplet
&lt;/h3&gt;

&lt;p&gt;If you want to use your own domain name (or sub-domain), add &lt;code&gt;A record&lt;/code&gt; in your domain name provider account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SrbQtU8a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/11.domain-a-record.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SrbQtU8a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/11.domain-a-record.png" alt="Domain to  MeiliSearch" width="880" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should work out of the box. Your domain should be usable for your MeiliSearch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KO0zbsK6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/11.working-domain.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KO0zbsK6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/11.working-domain.png" alt="Domain to  MeiliSearch" width="880" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Set API KEY and SSL (HTTPS)
&lt;/h3&gt;

&lt;p&gt;Meilisearch is running with a development configuration. It means that you haven't set up an API KEY (anyone can read/write from your MeiliSearch) and you aren't using HTTPS yet. But no worries, the configuration process is automated and very simple. Just connect via SSH to your new MeiliSearch Droplet and answer a few questions:&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1. Run the configuration script
&lt;/h3&gt;

&lt;p&gt;Open a terminal and start a new SSH connection with the IP you got from DigitalOcean.&lt;/p&gt;

&lt;p&gt;Write in your terminal &lt;code&gt;ssh root@&amp;lt;your-ip-address&amp;gt;&lt;/code&gt; and press Enter to establish connection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zBL65te9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/12.open-terminal-ssh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zBL65te9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/12.open-terminal-ssh.png" alt="Terminal ssh" width="473" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Write &lt;code&gt;yes&lt;/code&gt; and press Enter to accept the authentication process.&lt;/p&gt;

&lt;p&gt;A script will run automatically, asking for your settings and desired configuration. If you want to run this script again later, you can do so by typing:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sh /var/opt/meilisearch/scripts/first-login/000-set-meili-env.sh&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Enjoy your ready-to-use MeiliSearch droplet
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3IxKNfHm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/13.finish.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3IxKNfHm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/meilisearch/documentation/master/.vuepress/public/digitalocean/13.finish.png" alt="Enjoy" width="880" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoy&lt;/strong&gt;!&lt;/p&gt;

</description>
      <category>search</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>An alternative RubyGems search bar based on an opensource search engine</title>
      <dc:creator>curquiza</dc:creator>
      <pubDate>Thu, 30 Jan 2020 13:37:13 +0000</pubDate>
      <link>https://dev.to/meilisearch/an-alternative-rubygems-search-bar-base-on-an-opensource-search-engine-58j6</link>
      <guid>https://dev.to/meilisearch/an-alternative-rubygems-search-bar-base-on-an-opensource-search-engine-58j6</guid>
      <description>&lt;p&gt;As a Rails and Ruby lover, I often search for the gem that will perfectly cover my use case. When I need to solve a problem I'm having, I want to choose the right one, the most suitable solution.&lt;/p&gt;

&lt;p&gt;Ruby gems are extensive libraries created inside the Ruby community. The best place to find a ready solution for any task is the website rubygems.org, a public repository of gems that can be searched using the search box on the home page. RubyGems’ website is an efficient tool that facilitates the sharing and installation of packages. But although its search bar is very helpful, I decided to create an &lt;a href="https://rubygems.meilisearch.com"&gt;alternative search bar&lt;/a&gt; more suited to our needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1yge7zufzdia6jx3gilm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1yge7zufzdia6jx3gilm.png" alt="Rubygems alternative search bar" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made this project with &lt;a href="https://github.com/meilisearch/MeiliSearch"&gt;MeiliSearch&lt;/a&gt;, an opensource alternative to Algolia.&lt;/p&gt;

&lt;p&gt;The complete article is available &lt;a href="https://blog.meilisearch.com/meilisearch-finds-rubygems/"&gt;on our blog&lt;/a&gt;. I explain my approach in detail and how MeiliSearch works.&lt;/p&gt;

&lt;p&gt;Hope you will enjoy my first article! 😁&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>search</category>
      <category>webdev</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
