diff --git a/docs-site/content/.vuepress/config.js b/docs-site/content/.vuepress/config.js index a895010f..e4825a3d 100644 --- a/docs-site/content/.vuepress/config.js +++ b/docs-site/content/.vuepress/config.js @@ -149,6 +149,12 @@ let config = { ['/0.19.0/guide/features/typo-tolerance', 'Typo Tolerance'], ['/0.19.0/guide/features/faceting', 'Faceting'], ['/0.19.0/guide/features/filtering', 'Filtering'], + ['/0.19.0/guide/features/federated', 'Federated Search'], + ['/0.19.0/guide/features/scoped-API-keys', 'Scoped API Keys'], + ['/0.19.0/guide/features/synonyms', 'Synonyms'], + ['/0.19.0/guide/features/curation', 'Curation and Merchandizing'], + ['/0.19.0/guide/features/raft', 'Raft Based Clustering'], + ['/0.19.0/guide/features/upgrade', 'Seamless Version Upgrades'], ], }, ], diff --git a/docs-site/content/.vuepress/public/images/typesense-filter.png b/docs-site/content/.vuepress/public/images/typesense-filter.png index 1249e590..15da969d 100644 Binary files a/docs-site/content/.vuepress/public/images/typesense-filter.png and b/docs-site/content/.vuepress/public/images/typesense-filter.png differ diff --git a/docs-site/content/0.19.0/guide/features/federated.md b/docs-site/content/0.19.0/guide/features/federated.md new file mode 100644 index 00000000..9ed142fe --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/federated.md @@ -0,0 +1,182 @@ +# Federated Search + +Federated or multi search is a way to search for documents in multiple collections as part of a single search query. Federated search can help reduce network latencies. It can also be used to present similar content from other collections, that might encourage users to browse more content across your application. For example, your application might have different collections for `Nike` and `Adidas`. Now, if a user is looking for a shoe from a specific branch and they might not know what other brands are available, the search query can perform a search on both the collections and return relevant results from both the collections. + +Typesense supports searching across multiple collections in a single HTTP request. Let's create a search query for shoes: + +<Tabs :tabs="['JavaScript','PHP','Python','Ruby']"> + <template v-slot:JavaScript> + +```javascript +let searchRequests = { + 'searches': [ + { + 'collection': 'products', + 'q': 'shoe', + 'filter_by': 'price:=[50..120]' + }, + { + 'collection': 'brands', + 'q': 'Nike' + } + ] +} + +// Search parameters that are common to all searches go here +let commonSearchParams = { + 'query_by': 'name', +} + +client.multiSearch.perform(searchRequests, commonSearchParams) +``` + </template> + + <template v-slot:PHP> + +```php +$searchRequests = [ + 'searches' => [ + [ + 'collection' => 'products', + 'q' => 'shoe', + 'filter_by' => 'price:=[50..120]' + ], + [ + 'collection' => 'brands', + 'q' => 'Nike' + ] + ] +]; + +// Search parameters that are common to all searches go here +$commonSearchParams = [ + 'query_by' => 'name', +]; + +$client->multiSearch->perform($searchRequests, $commonSearchParams); +``` + </template> + <template v-slot:Python> + +```python +search_requests = { + 'searches': [ + { + 'collection': 'products', + 'q': 'shoe', + 'filter_by': 'price:=[50..120]' + }, + { + 'collection': 'brands', + 'q': 'Nike' + } + ] +} + +# Search parameters that are common to all searches go here +common_search_params = { + 'query_by': 'name', +} + +client.multi_search.perform(search_requests, common_search_params) +``` + </template> + <template v-slot:Ruby> + +```ruby +search_requests = { + 'searches': [ + { + 'collection': 'products', + 'q': 'shoe', + 'filter_by': 'price:=[50..120]' + }, + { + 'collection': 'brands', + 'q': 'Nike' + } + ] +} + +# Search parameters that are common to all searches go here +common_search_params = { + 'query_by': 'name', +} + +client.multi_search.perform(search_requests, common_search_params) +``` + </template> +</Tabs> + +Sample response: + +```json +{ + "results": [ + { + "facet_counts": [], + "found": 1, + "hits": [ + { + "document": { + "name": "Blue shoe", + "brand": "Adidas", + "id": "126", + "price": 50 + }, + "highlights": [ + { + "field": "name", + "matched_tokens": [ + "shoe" + ], + "snippet": "Blue <mark>shoe</mark>" + } + ], + "text_match": 130816 + } + ], + "out_of": 10, + "page": 1, + "request_params": { + "per_page": 10, + "q": "shoe" + }, + "search_time_ms": 1 + }, + { + "facet_counts": [], + "found": 1, + "hits": [ + { + "document": { + "name": "Nike shoes", + "brand": "Nike", + "id": "391", + "price": 60 + }, + "highlights": [ + { + "field": "name", + "matched_tokens": [ + "Nike" + ], + "snippet": "<mark>Nike</mark>shoes" + } + ], + "text_match": 144112 + } + ], + "out_of": 5, + "page": 1, + "request_params": { + "per_page": 10, + "q": "Nike" + }, + "search_time_ms": 1 + }, + ] +} +``` + +In the above example, the user is searching for a `Nike` shoe, but the `multiSerch` query returns results from the `Adidas` collection as well. You can control the number of maximum search requests using the `limit_multi_searches` parameter. By default, there is no limit. You can find more details on the argument [here](../../0.19.0/api/documents.html#federated-multi-search). diff --git a/docs-site/content/0.19.0/guide/features/raft.md b/docs-site/content/0.19.0/guide/features/raft.md new file mode 100644 index 00000000..2fbfdacc --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/raft.md @@ -0,0 +1,5 @@ +# Raft Based Clustering + +High availability is essential for production environments. Typesense uses [Raft algorithm](https://raft.github.io/) to create a highly available cluster with more than one Typesense servers. Based on raft consensus, to handle 1-node failure, you need to create a cluster with 3 nodes. Similarly for 2-node failure, you need to create a 5 node cluster. Note that adding more nodes will also add write latencies. + +More details on cluster operations can be found [here](../../api/cluster-operations.html). diff --git a/docs-site/content/0.19.0/guide/features/scoped-API-keys.md b/docs-site/content/0.19.0/guide/features/scoped-API-keys.md new file mode 100644 index 00000000..4f5e5705 --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/scoped-API-keys.md @@ -0,0 +1,47 @@ +# Scoped API Keys + +API keys are at the core of Typesense. To perform any action with Typesense, you need API keys. Typesense also allows access control on API keys. You can define capabilities as to what a user can or cannot do. You can also restrict access to a specific document or collection. In the case of a multi-tenant environment, you can scope API keys to a particular subset. This is helpful when you have indexed data from multiple tenants in your Typesense server and want to restrict users to only access their subset of data. + +Typesense allows you to create API keys that have pre-defined filters embedded in them. So, whenever you run a search query with these API keys, those filters are automatically applied and cannot be overridden. You can then provide those search API keys to users and they would only be able to access the data that is allowed by the set filter. To create scoped API keys, you just need a parent key. + +Let's create a scoped search API key that will restrict users to only access documents that have the company id 124: + +<Tabs :tabs="['JavaScript','PHP','Python','Ruby']"> + <template v-slot:JavaScript> + +```javascript +keyWithSearchPermissions = 'RN23GFr1s6jQ9kgSNg2O7fYcAUXU7127' +client.keys().generateScopedSearchKey(keyWithSearchPermissions, {'filter_by': 'company_id:124', 'expires_at': 1611590465}) +``` + </template> + + <template v-slot:PHP> + +```php +$keyWithSearchPermissions = 'RN23GFr1s6jQ9kgSNg2O7fYcAUXU7127'; +$client->keys()->generateScopedSearchKey($keyWithSearchPermissions, ['filter_by' => 'company_id:124', 'expires_at' => 1611590465]); +``` + </template> + <template v-slot:Python> + +```python +key_with_search_permissions = 'RN23GFr1s6jQ9kgSNg2O7fYcAUXU7127' +client.keys().generate_scoped_search_key(key_with_search_permissions, {"filter_by": "company_id:124", "expires_at": 1611590465}) +``` + </template> + <template v-slot:Ruby> + +```ruby +key_with_search_permissions = 'RN23GFr1s6jQ9kgSNg2O7fYcAUXU7127' +client.keys().generate_scoped_search_key(key_with_search_permissions, {'filter_by': 'company_id:124', 'expires_at': 1611590465}) +``` + </template> +</Tabs> + +Sample response: + +```json +"RDhxa2VKTnBQVkxaVlFIOS9JWDZ2bDdtMU5HL3laa0pab2pTeEUzbFBhZz1STjIzeyJmaWx0ZXJfYnkiOiJjb21wYW55X2lkOjEyNCIsImV4cGlyZXNfYXQiOjE2MTE1OTA0NjV9" +``` + +You can also set an expiration for scoped API keys using the `expires_at` parameter. You can find more details about scoped API keys [here](../../api/api-keys.html#generate-scoped-search-key). diff --git a/docs-site/content/0.19.0/guide/features/sorting.md b/docs-site/content/0.19.0/guide/features/sorting.md new file mode 100644 index 00000000..802150ba --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/sorting.md @@ -0,0 +1,94 @@ +# Sorting + +Sorting is the ordering of search results either in ascending or descending order based on a specific parameter. + +Typesense has in-built support for sorting. While creating a collection, you must define a `default_sorting_field`. Users can sort the results by defining the `sort_by` parameter in the search query. If `sort_by` field is not present, then the default field defined earlier would be used to sort results. For example, while searching for a book in a [books](../../api/#creating-a-books-collection) collection, the search query can be defined as: + +<Tabs :tabs="['JavaScript','PHP','Python','Ruby']"> + <template v-slot:JavaScript> + +```javascript +let searchParameters = { + 'q' : 'harry', + 'query_by' : 'title', + 'sort_by' : 'ratings_count:desc' +} + +client.collections('books').documents().search(searchParameters) +``` + </template> + + <template v-slot:PHP> + +```php +$searchParameters = [ + 'q' : 'harry', + 'query_by' : 'title', + 'sort_by' : 'ratings_count:desc' +]; + +$client->collections['books']->documents->search($searchParameters); +``` + </template> + <template v-slot:Python> + +```python +search_parameters = { + 'q' : 'harry', + 'query_by' : 'title', + 'sort_by' : 'ratings_count:desc' +} + +client.collections['books'].documents.search(search_parameters) +``` + </template> + <template v-slot:Ruby> + +```ruby +search_parameters = { + 'q' : 'harry', + 'query_by' : 'title', + 'sort_by' : 'ratings_count:desc' +} + +client.collections['books'].documents.search(search_parameters) +``` + </template> +</Tabs> + +Sample response: + +```json +{ + "facet_counts": [], + "found": 62, + "hits": [ + { + "highlights": [ + { + "field": "title", + "snippet": "<mark>Harry</mark> <mark>Potter</mark> and the Philosopher's Stone" + } + ], + "document": { + "authors": [ + "J.K. Rowling", "Mary GrandPré" + ], + "authors_facet": [ + "J.K. Rowling", "Mary GrandPré" + ], + "average_rating": 4.44, + "id": "2", + "image_url": "https://images.gr-assets.com/books/1474154022m/3.jpg", + "publication_year": 1997, + "publication_year_facet": "1997", + "ratings_count": 4602479, + "title": "Harry Potter and the Philosopher's Stone" + } + }, + ... + ] +} +``` + +Here the documents would be sorted by the `ratings_count` field in descending order. You can specify up to 3 fields for sorting. More details on using `sort_by` argument can be found [here](../../api/documents.html#arguments). diff --git a/docs-site/content/0.19.0/guide/features/synonyms.md b/docs-site/content/0.19.0/guide/features/synonyms.md new file mode 100644 index 00000000..a8d90640 --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/synonyms.md @@ -0,0 +1,69 @@ +# Synonyms + +Synonyms allow you to define equivalent search terms. For example, blazers and coats could be considered synonyms. Once these are defined as synonyms in Typesense, a search query for blazer would bring up results with coats as well. + +Typesense has two types of synonyms, one-way and multi-way. With one-way synonyms, you can define synonyms for one root word. In multi-way synonyms, you can define a set of words as synonyms. Let's define a one-way synonym for blazer: + +<Tabs :tabs="['JavaScript','PHP','Python','Ruby']"> + <template v-slot:JavaScript> + +```javascript +synonym = { + "root": "blazer", + "synonyms": ["coat", "jacket"] +} + +// Creates/updates a synonym called `blazer-synonyms` in the `products` collection +client.collections('products').synonyms().upsert('blazer-synonyms', synonym) +``` + </template> + + <template v-slot:PHP> + +```php +$synonym = [ + "root": "blazer", + "synonyms": ["coat", "jacket"] +]; + +// Creates/updates a synonym called `blazer-synonyms` in the `products` collection +$client->collections['products']->synonyms()->upsert('blazer-synonyms', $synonym); +``` + </template> + <template v-slot:Python> + +```python +synonym = { + "root": "blazer", + "synonyms": ["coat", "jacket"] +} + +# Creates/updates a synonym called `blazer-synonyms` in the `products` collection +client.collections['products'].synonyms().upsert('blazer-synonyms', synonym) +``` + </template> + <template v-slot:Ruby> + +```ruby +synonym = { + "root": "blazer", + "synonyms": ["coat", "jacket"] +} + +# Creates/updates a synonym called `blazer-synonyms` in the `products` collection +client.collections['products'].synonyms().upsert('blazer-synonyms', synonym) +``` + </template> +</Tabs> + +Sample response: + +```json +{ + "id":"coat-synonyms", + "root":"blazer", + "synonyms": ["coat", "jacket"] +} +``` + +In the above example, any query for blazer would bring up results for coat and jacket as well. For [multi-way synonym](../../api/synonyms.html#multi-way-synonym), you don't need to define the root word. You can find more details on synonyms [here](../../api/synonyms.html). diff --git a/docs-site/content/0.19.0/guide/features/upgrade.md b/docs-site/content/0.19.0/guide/features/upgrade.md new file mode 100644 index 00000000..ab90cfa9 --- /dev/null +++ b/docs-site/content/0.19.0/guide/features/upgrade.md @@ -0,0 +1,3 @@ +# Upgrades + +Typesense update process is outlined [here](../../guide/updating-typesense.html).