- How to Add Full-Text Search Functionality to Your JavaScript App
- What Is Full-Text Search?
- Setting Up Search Indexes
- Preparing Your Couchbase Instance
- Build a Basic Text Search Index
- Creating a Simple Text Search Function
- Full-text search in JavaScript (part II)
- A better solution to perform a full-text search in JavaScript
- forEach utility
- Recursive function to perform a full-text search in JavaScript
- Recursive cleaning function
- Final code for the full-text search in JavaScript
- Поиск по странице на JavaScript
- Как создать поиск на JavaScript:
How to Add Full-Text Search Functionality to Your JavaScript App
It’s unavoidable: If you’re working with a document database, you’re eventually going to need to search for (and through) your JSON documents.
In this tutorial, you’ll add the full-text search capabilities of Couchbase to the basic REST API built with Express that we’ve been building throughout this Node.js series.
Today’s post takes you a step further. You’ll learn how to find JSON documents that contain the text you’re after by adding functionality to your app that uses the Couchbase Search API. Let’s get started.
What Is Full-Text Search?
Full-text search (FTS) is a strange name, but it’s a well-developed concept in academic areas focused on analyzing large pieces of text content. In the database domain we just call it “search” for shorthand, and it’s focused on finding text within JSON documents.
Application developers use search-related tools to find matches without having to write SQL queries which usually require you to know how/where to find the data of interest. In a full-text search scenario you hunt for text with more sophistication.
For example, search systems understand root-words using a concept known as stemming, so you don’t have to look for many permutations of a term manually. Likewise, wildcards, prefixes, and fuzzy matching are possible with robust search systems.
Setting Up Search Indexes
There are two steps to using a Search system: (1) indexing/analyzing the text in each document and (2) requesting a list of documents that contain text-based matches.
The indexing stage is similar to creating secondary indexes for relational/tabular data where you describe the fields or elements to be indexed and the system keeps track of them for you. You can also just tell the system to index every text field in the document, though for large datasets this may not be efficient in production.
The querying stage (a.k.a., the search) sends a piece of text to the server for it to hunt for. The system compares that text to the indexes and returns a list of documents with matches.
Full-text search is straightforward, but there’s an infinite set of options and questions to consider, like:
-
- How to handle phrases and numbers
- Identifying where in a document particular text exists
- Analyzing text across multiple languages
Really, this is a deep-dive topic all of its own. The simple patterns used in this post can be expanded to all different search scenarios as described in this introduction to full-text search.
Preparing Your Couchbase Instance
If you are new to this series of JavaScript coding tutorials, you need to install the travel-sample data Bucket, as described in the Couchbase documentation.
The script used in the previous post of this series is also going to be used as a starting point for today’s post. The Node.js code is included at the end of that post.
As you progress through these Node.js tutorials you are building a more complex and useful REST API application. Let’s dive into creating the search index needed to support the next step of your project.
Build a Basic Text Search Index
To create a search index, you select the Search tab in the Couchbase Web Console and press the Add Index button.
Then enter the name you want to give the index and choose which Bucket to analyze ( travel-sample ). Finish by pressing the Create Index button to submit your choices. There are many different options to choose from, but in today’s example, we keep all the defaults for simplicity sake. The following animation shows each of these steps:
After completing these steps, you should see your search indexes and their status in the Web Console. You should also be able to see how many documents were processed.
Indexing on the travel-sample data Bucket takes a few minutes, but once it’s complete, you can do a sample search request through the basic web user interface as shown below.
You enter a simple term in the search box and a list of matching document IDs is returned with the highest-ranking matches at the top. The Web Console makes it easy to click on these IDs to see the full document text.
Creating a Simple Text Search Function
There are many additional options for fine-tuning your searches with boolean operations, fuzzy matching, and more. The Web Console only does a simple query string search and this is the same type you will implement in your code.
To create the new full-text search function you need to:
- Provide a string to search for (e.g., “grand”).
- Specify the search index to use: travelsearch .
- Declare the query type to use: queryString .
- Assemble all the parts together and send to server.
- Receive results and display to user/application.
These five lines of JavaScript code below are an example of setting these variables, bundling them together, passing to the cluster and printing the results to the console:
Full-text search in JavaScript (part II)
Some years ago, I wrote a post about how to perform a full-text search in JavaScript modifying the DOM to highlight the results.
The aforementioned post has been outdated and there are better ways to perform a search in JavaScript, without using complex regular expressions, and without rewriting completely the HTML container on each search.
A better solution to perform a full-text search in JavaScript
It is possible to just do a recursive search in all the elements inside the desired HTML container, focusing only on Element and Text nodes. If the node is of type Element, the search is performed again inside it, if the node is of type Text, we check if it contains a match of the search, if it does, we replace it by an element with the highlighted results, otherwise, we just ignore it.
forEach utility
Before anything, let‘s create a small utility to iterate through Element’s childNodes. For this purpose we can use the Array.prototype.forEach method.
The childNodes property of an Element returns a NodeList and this object contains a forEach method. But this method is not supported on Internet Explorer. If you don‘t need to cover this browser you can ignore this section and use the native method instead.
function forEach(node, callback)
In this way, we just need to do the next to iterate through the childNodes of an Element:
forEach(node, function (child) < // Do something with each child >);
Recursive function to perform a full-text search in JavaScript
Now, let‘s create a function to recursively search Text nodes in a container. If they contain a match inside, we just need to replace it with a span element that contains the original text with the matches, each one wrapped also in a span with a specific class.
/* ** Build a case insensitive regular expression that ** searches globaly for a specific text */ var reg = new RegExp("(" + search + ")", "gi"); function highlightSearchInNode (parentNode, search) < forEach(parentNode, function (node) < // If the node is a container, repeat the search inside it if (node.nodeType === 1) < highlightSearchInNode(node, search); // If the node is of type Text, check if it contains any match >else if ( node.nodeType === 3 && reg.test(node.nodeValue) ) < // Create a span element var span = document.createElement("span"); // Add a data attribute to the span to indentify it later span.dataset.search = "true"; // Insert the same text inside the span, replacing the matches with spans with a specific class span.innerHTML = node.nodeValue.replace(reg, "$1"); // Replace the node with the created span parentNode.replaceChild(span, node); > >); >
Using the previous function, if we search the word “can” in the next HTML code, the next result is returned:
Can you can the can that I can can?
Can you can the can that I can can?
Recursive cleaning function
Now we need a function to reset the container to its initial state (before performing a new search we need to start over a clean container).
function cleanAllSearchSpans (parentNode) < forEach(parentNode, function (node) < // If the node is of type Element if (node.nodeType === 1) < // If the node is of type span and it has the data-search property if ( node.nodeName === "SPAN" && node.dataset.search === "true" ) < // Replace the node with a Text node with the span inner text parentNode.replaceChild( document.createTextNode(node.innerText), node ); // Otherwise, repeat the search within the element >else < cleanAllSearchSpans(node); >> >); >;
Final code for the full-text search in JavaScript
With these two functions, it is possible to create a function that primarily cleans any previous search, then performs a new search and returns the number of matches (using the same regular expression):
function forEach(node, callback) < Array.prototype.forEach.call(node.childNodes, callback); >function searchText(container, search) < var total = 0; var reg = new RegExp("(" + search + ")", "gi"); var cleanAllSearchSpans = function (parentNode) < forEach(parentNode, function (node) < if (node.nodeType === 1) < if ( node.nodeName === "SPAN" && node.dataset.search === "true" ) < parentNode.replaceChild( document.createTextNode(node.innerText), node ); >else < cleanAllSearchSpans(node); >> >); >; var highlightSearchInNode = function (parentNode, search) < forEach(parentNode, function (node) < if (node.nodeType === 1) < highlightSearchInNode(node, search); >else if ( node.nodeType === 3 && reg.test(node.nodeValue) ) < var matches = node.nodeValue.match(reg); var span = document.createElement("span"); span.dataset.search = "true"; span.innerHTML = node.nodeValue.replace(reg, "$1"); parentNode.replaceChild(span, node); total += matches.length; > >); >; cleanAllSearchSpans(container); // Normalise the container to remove the text siblings nodes container.normalize(); highlightSearchInNode(container, search); return total; >
Поиск по странице на JavaScript
В этой статье мы разберём как сделать на JavaScript поиск на странице или если точнее по списку, будет крайне полезная и интересная статья.
Также рекомендую прочитать «Прогноз погоды на JavaScript», тоже крайне интересная и полезная статья.
Как создать поиск на JavaScript:
Для начала, перед созданием нам нужно сделать не большой HTML блок со списком, это делается всё очень просто, вот:
Здесь всё просто, мы просто создали не большой список, в котором храним ссылке, но это для примера.
Теперь перейдём самому главному, это самому поиску, для этого нам понадобится создать одну функцию, которая как раз и будет выполнять поиск, вот она:
В начале функции мы объявляем различного рода переменные, сначала берём наш input , потом создаём новую переменную присваиваем ей значение поля, но предварительно всю строку переводим в большой регистр, это нам пригодиться для сравнения.
Последнее берём ul и остальные элементы списка, который есть внутри него, проходимся по ним циклом, берём элемент a и сравниваем его, с переменной filter предварительно переводя высший регистр, всё это нужно, чтобы строки правильно сравнились, а при сравнение строк также учитывается и их регистр.
Если мы находим совпадение в строке ссылки, то тогда выставляем настройки display , пустую строку, иначе none , таким образом и работает поиск на JS.
Последние что нам осталось, это отследить, это событие нажатия клавиш, для этого вписываем такой код: