{"id":7700,"date":"2019-09-25T14:07:00","date_gmt":"2019-09-25T21:07:00","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=7700"},"modified":"2025-06-13T20:59:09","modified_gmt":"2025-06-14T03:59:09","slug":"introducing-fts-with-n1ql","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/","title":{"rendered":"Introducing FTS with N1QL"},"content":{"rendered":"<h5><b>Topics this article will cover<\/b><\/h5>\n<ol>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">What\u2019s good with N1QL?<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">What about FTS?<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">But why FTS within N1QL?<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Basic N1QL+FTS queries<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Deploying N1QL+FTS<\/span>\n<ol>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Syntax(es)<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Abilities &amp; limitations<\/span><\/li>\n<\/ol>\n<\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">N1QL+FTS Internals<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Covered-index vs Non-covered-index queries<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">More N1QL+FTS query examples<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">What&#8217;s next?<\/span><\/li>\n<\/ol>\n<h4><strong>1. Couchbase&#8217;s <a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/learn\/services-and-indexes\/services\/query-service.html\">N1QL<\/a><\/strong><\/h4>\n<ul>\n<li><span style=\"font-weight: 400;\">N1QL is Couchbase\u2019s SQL offering for manipulating JSON data stored within the couchbase server.<\/span><\/li>\n<li><span style=\"font-weight: 400;\">N1QL statements can be used to create, modify, drop indexes and select, insert, update, delete and upsert data into JSON documents.<\/span><\/li>\n<li><span style=\"font-weight: 400;\">N1QL expressions allow the user to perform aggregate, arithmetic, collection, comparison, conditional and several other operations.<\/span><\/li>\n<li><span style=\"font-weight: 400;\">All this comes with support from secondary indexes to enable these operations very efficiently.<\/span><\/li>\n<\/ul>\n<h4><strong>2. Couchbase&#8217;s <a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/learn\/services-and-indexes\/services\/search-service.html\">FTS<\/a><\/strong><\/h4>\n<ul>\n<li><span style=\"font-weight: 400;\">Couchbase\u2019s Full Text Search offering provides extensive capabilities for natural language querying and is meant to enable users to search text across multiple fields in JSON documents stored within a couchbase server.<\/span><\/li>\n<li><span style=\"font-weight: 400;\">It supports language-aware searching and scoring results based on relevancy which can be configured by the user.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">FTS sets up fast indexes that are very specially designed and meant to handle a wide range of text search workloads very efficiently.<\/span><\/li>\n<\/ul>\n<h4><b>3. Why support FTS via N1QL?<\/b><\/h4>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">N1QL queries can perform a search on strings, numbers, arrays etc. and with secondary indexing (b-tree index) &#8211; support point look up and range scans as well but FTS delivers performance for text search (simple and complex compound queries) with the support of its underlying inverted index.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Applications need the capability to leverage both the capabilities using a using a single API and language.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Supporting compound\/complex operations such as applying aggregations, arithmetic and other SQL operations over FTS results for ease-of development.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Extend FTS\u2019s visibility (more than just via SDK, curl or Couchbase\u2019s UI).<\/span><\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-7703 aligncenter\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/n1ql_n1fty_flow-1.jpg\" alt=\"\" width=\"608\" height=\"266\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1ql_n1fty_flow-1.jpg 608w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1ql_n1fty_flow-1-300x131.jpg 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1ql_n1fty_flow-1-20x9.jpg 20w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><b><\/b><\/p>\n<h4><b>4. N1QL + FTS<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Couchbase 6.5 will support the proposed interface between N1QL and FTS. The user will still be required to set up FTS indexes to support their use case just like with <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/learn\/services-and-indexes\/services\/index-service.html\"><span style=\"font-weight: 400;\">GSI<\/span><\/a><span style=\"font-weight: 400;\"> (Global Secondary Indexing). With this new interface, users will be allowed to merge and execute FTS queries from within N1QL queries seamlessly.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A new SEARCH(..) predicate will now be supported as part of the N1QL query syntax. Before getting into the internals of what goes on when a N1QL query with the SEARCH(..) predicate is executed, <a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/fts\/fts-creating-indexes.html\">here<\/a> is some documentation on how to create and manage FTS indexes and here are a few sample queries ..<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For example, say I have an FTS index set up over some travel documents, and I want to fetch the FTS results (just ids) for all documents carrying \u201cSan Francisco\u201d in their city field ..<\/span><\/p>\n<pre class=\"lang:default decode:true\">SELECT meta().id\nFROM `travel-sample` as t\nWHERE SEARCH(t, \u2018city:\u201dSan Francisco\u201d\u2019);\n<\/pre>\n<p><span style=\"font-weight: 400;\">As you can see above, the FTS query string \u2018city:\u201dSan Francisco\u201d\u2019 is embedded within the N1QL query. Alternatively, the N1QL query will also support a FTS query object such as ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cmatch_phrase\u201d: \u201cSan Francisco\u201d, \u201cfield\u201d: \u201ccity\u201d})\nLIMIT 10;\n<\/pre>\n<p><span style=\"font-weight: 400;\">The above example will limit the FTS result set to 10.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Or even a FTS search request object ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cquery\u201d: {\u201cmatch_phrase\u201d: \u201cSan Francisco\u201d, \u201cfield\u201d: \u201ccity\u201d}, \u201climit\u201d: 10});\n<\/pre>\n<p><span style=\"font-weight: 400;\">The above example also limits the result set to 10, but FTS will enforce it.<\/span><\/p>\n<p><i><span style=\"font-weight: 400;\">OFFSET\/LIMIT filters can be set either within the N1QL query syntax or within the FTS search request object. If these parameters are set within the FTS search request, FTS will stream only the requested number of results. N1QL parameters will be applied on whatever results FTS has sent it. If these settings are not set within the FTS object but are set in the N1QL query &#8211; FTS will stream all results to N1QL until such a time that N1QL has received all the results that it needs.<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400;\">Also, like in the last 3 examples, one doesn\u2019t have to explicitly specify the name of the FTS index to pick &#8211; N1QL will determine which is the best index among available ones to run the FTS query against. Should one want N1QL to use a specific index (for example &#8211; an index named \u201ctravel\u201d), here\u2019s how ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cmatch_phrase\u201d: \u201cSan Francisco\u201d, \u201cfield\u201d: \u201ccity\u201d}, {\u201cindex\u201d: \u201ctravel\u201d});\n<\/pre>\n<p><span style=\"font-weight: 400;\">Note that for all the example queries above &#8211; results are streamed and are not sorted based on relevance (score &#8211; default FTS behavior). Sorting can be achieved by explicitly stating it within the search request or using N1QLs\u2019 <\/span><i><span style=\"font-weight: 400;\">ORDER BY<\/span><\/i><span style=\"font-weight: 400;\"> clause. Pagination of results can also be achieved by only explicitly stating within the search request or by using N1QL\u2019s <\/span><i><span style=\"font-weight: 400;\">OFFSET<\/span><\/i><span style=\"font-weight: 400;\"> and <\/span><i><span style=\"font-weight: 400;\">LIMIT<\/span><\/i><span style=\"font-weight: 400;\"> clauses.<\/span><\/p>\n<h4><strong>5. Deploying N1QL + FTS<\/strong><\/h4>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">To allow N1QL queries with the SEARCH(..) capability, the couchbase cluster needs to have at least 1 node that runs the Search service and 1 node that runs the Query service (both these services can be configured on the same node as well).<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">FTS indexes are to be set up by user to index the necessary content that one wants to search over.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">If no FTS indexes were found by N1QL to execute the query, it searches for GSI indexes that can potentially handle the query. In this case, the SEARCH(..) predicate is applied on the intermediate results obtained.\u00a0 While this would work, it isn\u2019t the recommended approach since SEARCH(..) evaluation can be expensive.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">N1QL queries with SEARCH(..) can be run from the query workbench, curl, SDK or the command line interface that couchbase offers.<\/span><\/li>\n<\/ul>\n<h5><b>5.1 Search syntax<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">Here is what\u2019s supported within the SEARCH(&lt;field&gt;, &lt;FTS query&gt;, [options]) function..<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-7706\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM.png\" alt=\"\" width=\"1306\" height=\"558\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM.png 1306w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM-300x128.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM-1024x438.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM-768x328.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-2.00.02-PM-20x9.png 20w\" sizes=\"auto, (max-width: 1306px) 100vw, 1306px\" \/><\/p>\n<h5><b>5.2 Abilities &amp; limitations<\/b><\/h5>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">All the features that the FTS search requests offer will be supported by the N1QL queries.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\"><a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/fts\/fts-searching-with-the-rest-api.html\">Here<\/a> are some highlights on what to throw in the \u201cquery\u201d section within the SEARCH(..) function.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">FTS indexes that support multiple type mappings will be disallowed in the first release of N1QL+FTS interface so that false-positives wouldn\u2019t sneak in to the result set.<\/span><\/li>\n<\/ul>\n<h4><b style=\"color: #343e47; font-family: Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 30px;\">Internal Implementation<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Internally the N1QL+FTS interface supports 4 APIs that the N1QL service will invoke during its prepare and execution phases for queries with the SEARCH(..) predicate.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-7707\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM.png\" alt=\"\" width=\"1306\" height=\"324\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM.png 1306w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM-300x74.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM-1024x254.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM-768x191.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/Screen-Shot-2019-09-25-at-1.59.11-PM-20x5.png 20w\" sizes=\"auto, (max-width: 1306px) 100vw, 1306px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Before describing the above APIs in a little more detail, here\u2019s a flow chart of operations supported within the interface ..<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-7704 aligncenter\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/n1fty_flow-1.jpg\" alt=\"\" width=\"602\" height=\"750\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1fty_flow-1.jpg 602w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1fty_flow-1-241x300.jpg 241w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1fty_flow-1-300x374.jpg 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1fty_flow-1-16x20.jpg 16w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/p>\n<h5><b>6.1 Sargable<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">This FTS index API will be used to determine whether the index is capable of handling the query request without returning false negatives. In the first release, the index is only chosen if all the query fields are indexed within it, or the index has within its definition a dynamic mapping that would cater to all the requested fields. If multiple indexes are sargable for a given query, one that has the least number of fields indexed satisfying the sargability clause is chosen (for performance reasons).<\/span><\/p>\n<h5><b>6.2 Pageable<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">This API will be used to determine if the results obtained from the underlying FTS index will be pageable or not. If the index is pageable, N1QL will apply the filters (offset, limit, sort information) for FTS prior to issuing the Search(..), otherwise the filters are applied on the result set after FTS has shipped to it.<\/span><\/p>\n<p><i><span style=\"font-weight: 400;\">Note that this API is not invoked if there are no filters (offset, limit, order by) in the N1QL query.<\/span><\/i><\/p>\n<h5><b>6.3 Search<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">This API is invoked for the most sargable index, and is essentially responsible for getting the search request through to the FTS index and streaming results back from it via a channel. If the amount of data to stream exceeds the available buffer size at N1QL\u2019s end of the channel, FTS will backfill the data to a file and a separate routine is responsible for streaming this content to N1QL. This is done so that FTS\u2019s resources aren\u2019t held up by a slow connection from N1QL. Internally, the gRPC protocol is used for streaming data from FTS to N1QL.<\/span><\/p>\n<h5><b>6.4 Verify:Evaluate<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">This API is used by N1QL to ensure that the results\/hits returned by an FTS index are indeed valid for the query. FTS returns only the key-ids and some FTS related metadata (if requested) like score etc. N1QL fetched documents from KV and invokes Verify for them iff the SELECT predicate requests for some document fields.<\/span><\/p>\n<h4><b>Covered-index vs Non-covered-index queries<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">If the SELECT statement\u2019s predicate requests only keys or the metadata, the Verify API isn\u2019t invoked at all. This kind of a query is referred to as a <\/span><i><span style=\"font-weight: 400;\">covered-index query<\/span><\/i><span style=\"font-weight: 400;\">. If the request is for some other document content, N1QL will use the keys returned by FTS to fetch the document data from KV, after which it invokes the Verify method for each of the fetched documents to re-check whether the documents retrieved are indeed valid matches. This kind of a query is referred to as a <\/span><i><span style=\"font-weight: 400;\">non-covered-index query<\/span><\/i><span style=\"font-weight: 400;\">. Non-covered-index queries tend to have higher latencies than covered-index queries as they involve the KV fetch and verify for each hit.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">If the user requires other fields from the documents to be a part of the result set, a faster approach would be to tune the FTS index definition to store the desired fields. Now, in the search request within the SEARCH(..) function, include a section called \u201cfields\u201d: [\u201c*\u201d] to fetch all stored fields as part of the result set. This way N1QL will not have to do a separate document fetch and can skip the verify as well =&gt; essentially converting a non-covered-index query to a covered-index query at the cost of a larger FTS index.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Consider the following FTS index definition with fields \u201ccountry\u201d and \u201ccontent\u201d indexed..<\/span><\/p>\n<pre class=\"lang:default decode:true\">{\n  \"name\": \"sample\",\n  \"type\": \"fulltext-index\",\n  \"params\": {\n    \"mapping\": {\n      \"default_mapping\": {\n        \"enabled\": true,\n        \"dynamic\": true,\n        \"properties\": {\n          \"country\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"country\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"docvalues\": true\n              }\n            ]\n          },\n          \"content\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"content\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"docvalues\": true\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n<\/pre>\n<p><span style=\"font-weight: 400;\">Here\u2019s an example of a slower non-covered index query that fetches the document field \u201ccontent\u201d for documents that have \u201cunited states\u201d in their \u201ccountry\u201d field..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id, t.content\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cquery\u201d: {\u201cmatch_phrase\u201d: \u201cunited states\u201d, \u201cfield\u201d: \u201ccountry\u201d}})\nORDER BY search_score() DESC\nLIMIT 10;\n<\/pre>\n<p><span style=\"font-weight: 400;\">Lets update the index definition to also store the field \u201ccontent\u201d which is of interest..<\/span><\/p>\n<pre class=\"lang:default decode:true\">{\n  \"name\": \"sample\",\n  \"type\": \"fulltext-index\",\n  \"params\": {\n    \"mapping\": {\n      \"default_mapping\": {\n        \"enabled\": true,\n        \"dynamic\": true,\n        \"properties\": {\n          \"country\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"country\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"docvalues\": true\n              }\n            ]\n          },\n          \"content\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"content\",\n                \"type\": \"text\",\n                \"store\": true,\n                \"index\": true,\n                \"docvalues\": true\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n<\/pre>\n<p><span style=\"font-weight: 400;\">Now here\u2019s the same query that qualifies as a covered-index query..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta(t).id, meta.fields.content\nFROM `travel-sample` as t\nLET meta =\u00a0 search_meta(t)\nWHERE SEARCH(t, {\u201cquery\u201d: {\u201cmatch_phrase\u201d: \u201cunited states\u201d, \u201cfield\u201d: \u201ccountry\u201d}, \u201cfields\u201d: [\u201ccontent\u201d]})\nORDER BY search_score(t) DESC\nLIMIT 10;\n<\/pre>\n<h4><b>More N1QL+FTS examples<\/b><\/h4>\n<h5><b>8.1 Complex-er queries<\/b><\/h5>\n<p><i><span style=\"font-weight: 400;\">Running a compound conjunction\/disjunction FTS search within a N1QL query<\/span><\/i><span style=\"font-weight: 400;\"> \u2026 fetch top 100 document ids ordered by score (tf-idf .. which is FTS\u2019s default scoring algorithm) highest to lowest, whose category is landmark and country is United States..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id, search_score() as score\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cconjuncts\u201d: [{\u201cmatch\u201d: \u201clandmark\u201d, \u201cfield\u201d: category\u201d}, {\u201cmatch_phrase\u201d: \u201cunited states\u201d, \u201cfield\u201d: \u201ccountry\u201d}]})\nORDER BY score DESC\nLIMIT 100;\n<\/pre>\n<p><span style=\"font-weight: 400;\">Here\u2019s an equivalent query with embedded FTS settings within the SEARCH(..) function \u2026<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id, search_score() as score\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cquery\u201d: {\u201cconjuncts\u201d: [{\u201cmatch\u201d: \u201clandmark\u201d, \u201cfield\u201d: category\u201d}, {\u201cmatch_phrase\u201d: \u201cunited states\u201d, \u201cfield\u201d: \u201ccountry\u201d}]}, \u201csort\u201d: [\u201c-_score\u201d], \u201climit\u201d: 10});\n<\/pre>\n<p><i><span style=\"font-weight: 400;\">Running another query with FTS settings embedded within the SEARCH(..) function<\/span><\/i><span style=\"font-weight: 400;\"> \u2026 fetch all document ids that contain within their description field the term gothic without considering score. Here we can optimize the FTS search request to not determine score at all..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id\nFROM `travel-sample` as t\nWHERE SEARCH(t, {\u201cquery\u201d: {\u201cmatch\u201d: \u201cgothic\u201d, \u201cfield\u201d: \u201cdescription\u201d}, \u201cscore\u201d: \u201cnone\u201d});\n<\/pre>\n<p><span style=\"font-weight: 400;\">Various FTS query types that are supported are described in more detail <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/fts\/fts-query-types.html\"><span style=\"font-weight: 400;\">here<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h5><b>8.2 Query sargability vs Index definitions<\/b><\/h5>\n<p><span style=\"font-weight: 400;\">Before we jump into some examples on how queries are deemed sargable for FTS index definitions, learn more about FTS index definitions <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/6.5\/fts\/fts-creating-indexes.html\"><span style=\"font-weight: 400;\">here<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Consider the following query, which looks for term \u201cgothic\u201d in the field \u201cdescription\u201d ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">SELECT meta().id, search_score() \nFROM `travel-sample`\nWHERE SEARCH(`travel-sample`, {\u201cquery\u201d: {\u201cmatch\u201d: \u201cgothic\u201d, \u201cfield\u201d: \u201cdescription\u201d});\n<\/pre>\n<p><span style=\"font-weight: 400;\">In the couchbase system at hand, let\u2019s assume there are several FTS indexes defined.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The first FTS index we encounter has the following definition ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">{\n  \"type\": \"fulltext-index\",\n  \"params\": {\n    \"mapping\": {\n      \"default_mapping\": {\n        \"enabled\": true,\n        \"dynamic\": true\n      }\n    }\n  }\n}<\/pre>\n<p><span style=\"font-weight: 400;\">This index is what is referred to as a default dynamic index which covers all fields available across all documents and also includes content within the default field \u201c_all\u201d. This default field is what is looked into when an FTS query does not carry \u201cfield\u201d information for a search criteria. <span style=\"text-decoration: underline;\"><em>This index is deemed SARGABLE for the above query<\/em><\/span>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A second FTS index is found to have the following definition ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">{\n  \"type\": \"fulltext-index\",\n  \"params\": {\n    \"mapping\": {\n      \"default_mapping\": {\n        \"enabled\": true,\n        \"dynamic\": false,\n        \"properties\": {\n          \"description\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"description\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"include_in_all\": false,\n                \"docvalues\": true\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}<\/pre>\n<p><span style=\"font-weight: 400;\">This index only has the field \u201cdescription\u201d indexed, which would cater to the query\u2019s request, and hence <em><span style=\"text-decoration: underline;\">the index is SARGABLE for the query<\/span><\/em>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A third FTS index is found to have the following definition ..<\/span><\/p>\n<pre class=\"lang:default decode:true \">{\n  \"type\": \"fulltext-index\",\n  \"params\": {\n    \"mapping\": {\n      \"default_mapping\": {\n        \"enabled\": true,\n        \"dynamic\": false,\n        \"properties\": {\n          \"city\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"city\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"include_in_all\": true,\n                \"docvalues\": true\n              }\n            ]\n          },\n          \"country\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"country\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"include_in_all\": true,\n                \"docvalues\": true\n              }\n            ]\n          },\n          \"name\": {\n            \"enabled\": true,\n            \"dynamic\": false,\n            \"fields\": [\n              {\n                \"name\": \"name\",\n                \"type\": \"text\",\n                \"store\": false,\n                \"index\": true,\n                \"include_term_vectors\": true,\n                \"include_in_all\": false,\n                \"docvalues\": true\n              }\n            ]\n          }\n        }\n      }\n    }\n  }\n}<\/pre>\n<p><span style=\"font-weight: 400;\">This index has a few fields indexed but none of them match the requested field \u201cdescription\u201d. <em><span style=\"text-decoration: underline;\">This index is deemed NOT-SARGABLE for the query<\/span><\/em><em>.<\/em><\/span><\/p>\n<p><i><span style=\"font-weight: 400;\">N1QL now has the option to select from the first 2 indexes which will be able to deliver accurate results for the query. Since the number of fields indexed within the second index is precise and smaller (and therefore since the search across this index would be faster), N1QL chooses the second index for execution of the query.<\/span><\/i><\/p>\n<h4><b>Future<\/b><\/h4>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Establishing sargability better by supporting some flexibility of the FTS index definitions &#8211; as in FTS indexes that don\u2019t support all the requested fields.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Support for FTS indexes with multiple type mappings.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Extending N1QL query interface to edit FTS indexes.<\/span><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Topics this article will cover What\u2019s good with N1QL? What about FTS? But why FTS within N1QL? Basic N1QL+FTS queries Deploying N1QL+FTS Syntax(es) Abilities &amp; limitations N1QL+FTS Internals Covered-index vs Non-covered-index queries More N1QL+FTS query examples What&#8217;s next? 1. Couchbase&#8217;s [&hellip;]<\/p>\n","protected":false},"author":37266,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1821,2165,1812],"tags":[],"ppma_author":[8925],"class_list":["post-7700","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-architecture","category-full-text-search","category-n1ql-query"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.7.1 (Yoast SEO v25.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Introducing FTS with N1QL - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Introducing FTS with N1QL\" \/>\n<meta property=\"og:description\" content=\"Topics this article will cover What\u2019s good with N1QL? What about FTS? But why FTS within N1QL? Basic N1QL+FTS queries Deploying N1QL+FTS Syntax(es) Abilities &amp; limitations N1QL+FTS Internals Covered-index vs Non-covered-index queries More N1QL+FTS query examples What&#8217;s next? 1. Couchbase&#8217;s [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-09-25T21:07:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T03:59:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1ql_n1fty_flow-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"608\" \/>\n\t<meta property=\"og:image:height\" content=\"266\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Abhinav Dangeti, Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Abhinav Dangeti, Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\"},\"author\":{\"name\":\"Abhinav Dangeti, Software Engineering, Couchbase inc.\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/574480df99d76a8837bba934d7324711\"},\"headline\":\"Introducing FTS with N1QL\",\"datePublished\":\"2019-09-25T21:07:00+00:00\",\"dateModified\":\"2025-06-14T03:59:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\"},\"wordCount\":2041,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Architecture\",\"Full-Text Search\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\",\"name\":\"Introducing FTS with N1QL - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2019-09-25T21:07:00+00:00\",\"dateModified\":\"2025-06-14T03:59:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Introducing FTS with N1QL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/574480df99d76a8837bba934d7324711\",\"name\":\"Abhinav Dangeti, Software Engineering, Couchbase inc.\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/9fa9293925a63fb1fab65e43636c534b\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6119ccf4cd5cba9ca4abd6f338d737445c23575e60f2b2729806c28185d0ee9b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6119ccf4cd5cba9ca4abd6f338d737445c23575e60f2b2729806c28185d0ee9b?s=96&d=mm&r=g\",\"caption\":\"Abhinav Dangeti, Software Engineering, Couchbase inc.\"},\"description\":\"Work on Couchbase's Distributed Full Text Search\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/abhinav\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Introducing FTS with N1QL - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/","og_locale":"en_US","og_type":"article","og_title":"Introducing FTS with N1QL","og_description":"Topics this article will cover What\u2019s good with N1QL? What about FTS? But why FTS within N1QL? Basic N1QL+FTS queries Deploying N1QL+FTS Syntax(es) Abilities &amp; limitations N1QL+FTS Internals Covered-index vs Non-covered-index queries More N1QL+FTS query examples What&#8217;s next? 1. Couchbase&#8217;s [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/","og_site_name":"The Couchbase Blog","article_published_time":"2019-09-25T21:07:00+00:00","article_modified_time":"2025-06-14T03:59:09+00:00","og_image":[{"width":608,"height":266,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/n1ql_n1fty_flow-1.jpg","type":"image\/jpeg"}],"author":"Abhinav Dangeti, Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Abhinav Dangeti, Software Engineer","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/"},"author":{"name":"Abhinav Dangeti, Software Engineering, Couchbase inc.","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/574480df99d76a8837bba934d7324711"},"headline":"Introducing FTS with N1QL","datePublished":"2019-09-25T21:07:00+00:00","dateModified":"2025-06-14T03:59:09+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/"},"wordCount":2041,"commentCount":2,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Best Practices and Tutorials","Couchbase Architecture","Full-Text Search","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/","url":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/","name":"Introducing FTS with N1QL - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2019-09-25T21:07:00+00:00","dateModified":"2025-06-14T03:59:09+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/introducing-fts-with-n1ql\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Introducing FTS with N1QL"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/574480df99d76a8837bba934d7324711","name":"Abhinav Dangeti, Software Engineering, Couchbase inc.","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/9fa9293925a63fb1fab65e43636c534b","url":"https:\/\/secure.gravatar.com\/avatar\/6119ccf4cd5cba9ca4abd6f338d737445c23575e60f2b2729806c28185d0ee9b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6119ccf4cd5cba9ca4abd6f338d737445c23575e60f2b2729806c28185d0ee9b?s=96&d=mm&r=g","caption":"Abhinav Dangeti, Software Engineering, Couchbase inc."},"description":"Work on Couchbase's Distributed Full Text Search","url":"https:\/\/www.couchbase.com\/blog\/author\/abhinav\/"}]}},"authors":[{"term_id":8925,"user_id":37266,"is_guest":0,"slug":"abhinav","display_name":"Abhinav Dangeti, Software Engineer","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/6119ccf4cd5cba9ca4abd6f338d737445c23575e60f2b2729806c28185d0ee9b?s=96&d=mm&r=g","author_category":"","last_name":"Dangeti, Software Engineer","first_name":"Abhinav","job_title":"","user_url":"","description":"Work on Couchbase's Distributed Full Text Search"}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7700","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/37266"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=7700"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7700\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=7700"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=7700"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=7700"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7700"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}