A newer version of this documentation is available.

View Latest

Add Autocomplete to Your Application

  • how-to
    +
    Use autocomplete to add suggestions for a user’s Search query as they type in your application.

    After you create and configure a Search index that supports autocomplete, configure your application to return results from the Search Service.

    Prerequisites

    • You’ve deployed the Search Service on a node in your database.

    • You have a bucket with scopes and collections in your database.

    • Your user account has the Search Admin role for the bucket where you want to create the index.

    • You’ve created a compatible Search index. For more information, see Configure an Autocomplete Search Index.

    Procedure

    To add autocomplete with the Serach Service to your application:

    1. To test that your Search index was configured correctly, do one of the following:

      1. Run a Search query from the REST API with 2-8 characters in the query property.

      2. Run a Search query from the Web Console with 2-8 characters in the Search field.

      For example, with the travel-sample bucket, you could enter the strings Be, Bea, Beau, and Beauf to find a document with the text Beaufort Hotel.

    2. Configure your application to return results from the Search Service.

      The following examples simulate a user typing an input string and return search results for each partial string:

      • C#

      • Go

      • Java

      • JavaScript

      • Python

      using Couchbase;
      using Couchbase.Search.Queries.Simple;
      
      await using var cluster = await Cluster.ConnectAsync(new ClusterOptions
      {
          ConnectionString = "CB_HOSTNAME",
          UserName = "CB_USERNAME",
          Password = "CB_PASSWORD",
          Buckets = new List<string>{"travel-sample"}
      }.ApplyProfile("wan-development"));
      
      var searchString = "Beaufort Hotel";
      for (var i = 2; i <= 8; i++)
      {
          var lettersEntered = searchString.Substring(0, i);
          Console.WriteLine($"Input <{lettersEntered}>, len: {lettersEntered.Length}");
          await FtsMatchPrefix(lettersEntered);
      }
      
      async Task FtsMatchPrefix(string letters)
      {
          try
          {
              var results = await cluster.SearchQueryAsync("e-ngram-2-8",
                  new QueryStringQuery(letters),
                  options =>
                  {
                      options.Limit(8);
                      options.Fields("name");
                  });
              results.Hits.ToList().ForEach(row => { Console.WriteLine($"{row.Id}, {row.Fields}"); });
              Console.WriteLine(results);
          }
          catch (Exception e)
          {
              Console.WriteLine(e);
          }
      }
      package main
      
      import (
          "os"
          "fmt"
          "math"
          "log"
          "github.com/couchbase/gocb/v2"
          "github.com/couchbase/gocb/v2/search"
      )
      
      func main() {
          cluster, err := gocb.Connect(
      	os.Getenv("CB_HOSTNAME"),                    
      	gocb.ClusterOptions{
              Authenticator: gocb.PasswordAuthenticator{
                  Username: os.Getenv("CB_USERNAME"),      
                  Password: os.Getenv("CB_PASSWORD"),      
              },
          })
          if err != nil {
              log.Fatal(err)
          }
      
          iterStr := "Beaufort Hotel"
          maxsz := int(math.Min(float64(len(iterStr)), float64(8)))
          for i := 2;  i <= maxsz; i++ {
              testStr := iterStr[0:i]
      	fmt.Printf("Input <%s>, len: %d\n", testStr, len(testStr));
      	results, err := cluster.SearchQuery(
      	    "e-ngram-2-8",
      	    search.NewQueryStringQuery(testStr), 
      	    &gocb.SearchOptions { Fields: []string{"name"}, Limit: 8, },
      	)
      	if err != nil {
      	    log.Fatal(err)
      	}
      
      	for results.Next() {
      	    row := results.Row()
      	    docID := row.ID
      	    var fields interface {}
      	    err := row.Fields( & fields)
      	    if err != nil {
      		panic(err)
      	    }
      	    fmt.Printf("Document ID: %s, fields: %v\n", docID, fields)
      	}
      
      	err = results.Err()
      	if err != nil {
      	    log.Fatal(err)
      	}
          }
      }
      import com.couchbase.client.java.Cluster;
      import com.couchbase.client.java.json.JsonObject;
      import com.couchbase.client.java.search.SearchOptions;
      import com.couchbase.client.java.search.SearchQuery;
      import com.couchbase.client.java.search.result.SearchResult;
      import com.couchbase.client.java.search.result.SearchRow;
      
      public class MockTypeAheadEnGram {
        static String connstrn = System.getenv("CB_HOSTNAME"); 
        static String username = System.getenv("CB_USERNAME"); 
        static String password = System.getenv("CB_PASSWORD"); 
        
        public static void main(String... args) {
          Cluster cluster = Cluster.connect(connstrn, username, password);
          
          String iterStr = "Beaufort Hotel";
          for (int i=2; i<=Math.min(8, iterStr.length());i++) {
          	String testStr = iterStr.substring(0, i);
          	System.out.println("Input <" + testStr + ">, len: " + testStr.length());
          
          	SearchQuery query = SearchQuery.queryString(testStr);
          	SearchOptions options = SearchOptions.searchOptions().limit(8).skip(0).explain(false).fields("name");
          	SearchResult result = cluster.searchQuery("e-ngram-2-8" , query, options);
          	for (SearchRow row : result.rows()) {
          		System.out.println(row.id() + "," + row.fieldsAs(JsonObject.class) );
          	}
          }
        }
      }
      const couchbase = require('couchbase')
      
      const main = async () => {
        const hostname = process.env.CB_HOSTNAME
        const username = process.env.CB_USERNAME
        const password = process.env.CB_PASSWORD
        const bucketName = 'travel-sample'
      
        const cluster = await couchbase.connect(hostname, {username: username, password: password })
      
        const ftsMatchPrefix = async (term) => {
          try {
            const result =  await cluster.searchQuery(
              "e-ngram-2-8",
              couchbase.SearchQuery.queryString(term), { limit: 8, fields: ["name"] }
            )
            result.rows.forEach((row) => { console.log(row.id,row.fields)})
          } catch (error) {
            console.error(error)
          }
        }
      
        const inputStr = "Beaufort Hotel"
        for (let i = 2; i <= 8; i++) {
          var testStr = inputStr.substring(0, i);
          console.log("Input <" + testStr + ">, len: " + testStr.length)
          const res = await ftsMatchPrefix(testStr)
        }
      }
      
      main()
      from couchbase.cluster import Cluster, ClusterOptions
      from couchbase.auth import PasswordAuthenticator
      from couchbase.exceptions import CouchbaseException
      import couchbase.search as search
      import os
      
      username = os.getenv("CB_USERNAME", default=None)
      password = os.getenv("CB_PASSWORD", default=None)
      hostname = os.getenv("CB_HOSTNAME", default=None)
      
      cluster = Cluster.connect(
          "couchbase://" + hostname,
          ClusterOptions(PasswordAuthenticator(username,password)))
      
      try:
          inputStr = "Beaufort Hotel"
          for i in range(2, min(8,len(inputStr))):
              testStr = inputStr[0:i]
              print("Input <" + testStr + ">, len: " + str(len(testStr)));
      
              result = cluster.search_query(
                  "e-ngram-2-8", 
                  search.QueryStringQuery(testStr),
                  search.SearchOptions(limit=8, fields=["name"]))
      
              for row in result.rows():
                  print(row.id,row.fields)
      
      except CouchbaseException as ex:
          import traceback
          traceback.print_exc()

    Next Steps

    After you add autocomplete to your application, to improve your search results, you can: