Skip to content

Full-Text Search

Once you have your SDK for your preferred language installed, you can start performing full-text, vector, and hybrid search queries on Orama Cloud.

The client exposes a simple search method that can be used to query the index:

import { OramaClient } from "@oramacloud/client";
const client = new OramaClient({
endpoint: '<Your Orama Cloud Endpoint>',
api_key: '<Your Orama Cloud API Key>',
});
const results = await client.search({
term: "red shoes",
mode: "fulltext", // optional, default is "fulltext" but can also be "vector" or "hybrid"
where: {
price: {
gt: 99.99,
},
},
});

Sorting

To perform sorting, Orama Cloud uses the properties defined in the schema to know on which properties you want to perform sorting.

Considering the following schema:

{
"title": "string",
"year": "number",
"inPromotion": "boolean",
"meta": {
"tag": "string",
"rating": "number",
"favorite": "boolean"
}
}
const results = await client.search({
term: "prestige",
sortBy: {
property: "year",
order: "desc" // optional, default is "asc"
},
});

With Orama Cloud, you can set up to three sorting properties. This means that you can sort by up to three properties at the same time.

So, considering the following schema:

{
"title": "string",
"year": "number",
"inPromotion": "boolean",
"meta": {
"tag": "string",
"rating": "number",
"favorite": "boolean"
}
}

You can sort by year and meta.rating at the same time:

const results = await client.search({
term: "prestige",
sortBy: [
{
property: "year",
order: "desc"
},
{
property: "meta.rating",
order: "desc"
}
]
});

In that case, “year” will be the primary sorting property, and “meta.rating” will be the secondary sorting property. In case of a tie, the secondary sorting property will be used to break the tie.

Facets

Facets are a powerful tool for filtering and narrowing down search results on the Orama search engine.

With the Orama Faceted Search API, users can filter their search results by various criteria, such as category, price range, or other attributes, making it easier to find the information they need. Whether you’re building a website, mobile app, or any other application, the Orama Faceted Search API is the perfect solution for adding faceted search functionality to your project.

Given the following Orama schema:

schema.json
{
"title": "string",
"description": "string",
"categories": {
"primary": "string",
"secondary": "string",
},
"rating": "number",
"isFavorite": "boolean",
}

Orama will be able to generate facets at search-time based on the schema. To do so, we need to specify the facets property in the search configuration:

const results = await client.search({
term: "Movie about cars and racing",
mode: "hybrid",
properties: ["description"],
facets: {
"categories.primary": {
limit: 3,
order: "DESC",
},
"categories.secondary": {
limit: 2,
order: "DESC",
},
rating: {
ranges: [
{ from: 0, to: 3 },
{ from: 3, to: 7 },
{ from: 7, to: 10 },
],
},
isFavorite: {
true: true,
false: true,
},
},
});

This will generate the following result:

{
"elapsed": ...,
"count": ...,
"hits": { ... },
"facets": {
"categories.first": {
"count": 14,
"values": {
"Action": 4,
"Adventure": 3,
"Comedy": 2,
}
},
"categories.second": {
"count": 14,
"values": {
"Cars": 4,
"Racing": 3,
}
},
"rating": {
"count": 3,
"values": {
"0-3": 5,
"3-7": 15,
"7-10": 80,
}
},
"isFavorite": {
"count": 2,
"values": {
"true": 5,
"false": 95,
}
},
}
}

As you may have noticed, the facets property is an object that contains different configurations depending on the property type specified in the schema.

String facets

If a property is specified as string in the schema, the facet will accept the following configuration:

PropertyTypeDefaultDescription
orderstringDESCOrder of the values. Can be either ASC or DESC.
limitnumber10Maximum number of values to return.
offsetnumber0Number of values to skip.

In the search result, string facets will be returned as an object with the following properties:

{
"count": 14, // Total number of values, now limited to 3 (size)
"values": {
"Action": 4, // Number of documents that have this value
"Adventure": 3, // Number of documents that have this value
"Comedy": 2, // Number of documents that have this value
}
}

Number facets

If a property is specified as number in the schema, the facet will accept the following configuration:

PropertyTypeDefaultDescription
rangesarray[]Array of ranges to consider.

Each range is an object with the following properties:

PropertyTypeDescription
fromnumberMinimum value of the range.
tonumberMaximum value of the range.

In the search result, number facets will be returned as an object with the following properties:

{
"count": 3, // Total number of ranges
"values": {
"0-3": 5, // Number of documents that have a value between 0 and 3 (inclusive)
"3-7": 15, // Number of documents that have a value between 3 and 7 (inclusive)
"7-10": 80, // Number of documents that have a value between 7 and 10 (inclusive)
}
}

Please note that the from and to values are inclusive. Note also that the order of the ranges is guaranteed as specified in the configuration.

Boolean facets

If a property is specified as boolean in the schema, the facet will accept the following configuration:

PropertyTypeDefaultDescription
truebooleantrueWhether to consider true values.
falsebooleantrueWhether to consider false values.

In the search result, boolean facets will be returned as an object with the following properties:

{
"count": 2, // Total number of values
"values": {
"true": 5, // Number of documents that have a `true` value
"false": 95, // Number of documents that have a `false` value
}
}

Enum facets

If a property is specified as enum in the schema, no configuration is required. In the search result, enum facets will be returned as an object with the following properties:

{
"count": 9, // Total number of values
"values": {
"Action": 4, // Number of documents that have this value
"Adventure": 3, // Number of documents that have this value
"Comedy": 2, // Number of documents that have this value
}
}

Filters

You can use the filters interface to filter the search results.

Filters are available for numeric, boolean, string, enum, and geopoint properties. Depending on the type of the property, you can use different operators.

Filtering by string properties

On string properties it performs an exact matching on tokens so it is advised to disable stemming for the properties you want to use filters on (when using the default tokenizer you can provide the stemmerSkipProperties configuration property).

If we consider the following schema:

{
"title": "string",
"tag": "string",
}
const results = client.search({
term: "prestige",
where: {
tag: "new",
},
});

The results will contain all documents that contain the word prestige in the title property and have tags property equal to new.

You can also specify a list of string, in this case, it will return all documents that contain at least one of the values provided:

const results = await client.search({
term: "prestige",
where: {
tag: ["favorite", "new"],
},
});

Filtering by number properties

The number properties supports the following operators:

OperatorDescriptionExample
gtGreater thanyear: { gt: 2000 }
gteGreater than or equal toyear: { gte: 2000 }
ltLess thanyear: { lt: 2000 }
lteLess than or equal toyear: { lte: 2000 }
eqEqual toyear: { eq: 2000 }
betweenBetween two values (inclusive)year: { between: [2000, 2008] }

So, considering the following schema:

{
"title": "string",
"year": "number",
"meta": {
"rating": "number",
"length": "number",
"favorite": "boolean",
"tags": "string",
}
}

You can filter the results by the meta.rating property as follows:

const results = await client.search({
term: "prestige",
where: {
year: {
gte: 2000,
},
"meta.rating": {
between: [5, 10],
},
"meta.length": {
lte: 60,
},
},
});

Filtering by boolean properties

For boolean properties, you can simply set the property to true or false:

const results = await client.search({
term: "prestige",
where: {
"meta.favorite": true,
},
});

Filtering by enum properties

The enum properties support the following operators:

OperatorDescriptionExample
eqEqual togenre: { eq: 'drama' }
inContained in the given arraygenre: { in: ['drama', 'horror'] }
ninNot contained in the given arraygenre: { nin: ['commedy'] }

Filtering by Enum[] properties

The enum properties support the following operators:

OperatorDescriptionExample
containsAllContains all the given valuesgenre: { containsAll: ['comedy', 'action'] }

Geosearch

Geosearch is a feature that allows you to filter your search results by distance from a given location, or by bounding box.

To perform geosearch queries, you first have to define a new geopoint property inside your schema definition when creating your Orama instance:

{
"name": "string",
"location": "geopoint",
}

What are geopoints

A geopoint is an object with two properties: lat and lon, which are both numbers. For reference, the following is a valid geopoint:

{
"lat": 45.46409,
"lon": 9.19192
}

As you may guess, lat stands for latitude, and lon for longitude. The values are expressed in degrees, and can be positive or negative.

Inserting documents with geopoints

When inserting documents containing geopoints, you’ll have to provide the lat and lon properties as floating-point numbers. For example, considering the following schema:

{
"name": "string",
"location": "geopoint"
}

We would have to insert the following docs:

[
{
"name": "Duomo di Milano",
"location": {
"lat": 45.46409,
"lon": 9.19192
}
},
{
"name": "Piazza Duomo",
"location": {
"lat": 45.46416,
"lon": 9.18945
}
},
{
"name": "Piazzetta Reale",
"location": {
"lat": 45.46339,
"lon": 9.19092
}
}
]

Given the points above, we can picture them on a map as follows:


To avoid confusion, please note that Orama is a full-text and vector search library. We do not provide the tools to draw on maps.

Now that we have some data, let’s see how we can perform geosearch queries.

Performing geosearch queries

When performing geosearch queries, we have to decide whether we want to filter our results by distance from a given location, or by bounding polygon.

When filtering by distance, we select a central coordinate and a radius of a given length, and we return all the documents that are within that radius from the central coordinate.

When filtering by bounding polygon, we select a polygon on the map, and we return all the documents that are within that polygon.

Filtering by distance (radius)

To filter by distance, we use the radius property. Let’s see how it works:

const searchResult = await client.search({
term: 'Duomo',
where: {
location: { // The property we want to filter by
radius: { // The filter we want to apply (in that case: "radius")
coordinates: { // The central coordinate
lat: 45.4648,
lon: 9.18998
},
unit: 'm', // The unit of measurement. The default is "m" (meters)
value: 1000, // The radius length. In that case, 1km
}
}
}
})

The geopoint { lat: 45.4648, lon: 9.18998 } represents the entrance of the Vittorio Emanuele II Gallery in Milan, nearby the Duomo.

If we follow the configuration above, we are asking Orama to return all the documents that are within 100 meters from the Gallery, as shown in the following map:

The query above will return only one result indeed: the Piazza Duomo document.

If we change the inside property to false, we will get the opposite result: all the documents that are outside the radius.

Supported units of measurement

Orama currently supports the following units of measurement:

  • cm (centimeters)
  • m (meters)
  • km (kilometers)
  • ft (feet)
  • yd (yards)
  • mi (miles)

All these units will be converted into meters automatically. If you feel like we should support other units of measurement, please open an issue

Filtering by bounding polygon

To filter by bounding polygon, we use the polygon property. Let’s see how it works:

const searchResult = await search(db, {
term: 'Duomo',
where: {
location: { // The property we want to filter by
polygon: { // The filter we want to apply (in that case: "polygon")
coordinates: [ // The polygon coordinate
{ lat: 45.46472, lon: 9.1886 },
{ lat: 45.46352, lon: 9.19177 },
{ lat: 45.46278, lon: 9.19176 },
{ lat: 45.4628, lon: 9.18857 },
{ lat: 45.46472, lon: 9.1886 },
]
}
}
}
})

If we try to draw the polygon above on our map, we will get the following result:

The query above will return only one result: Piazza Duomo. This is because it will filter all the documents inside the polygon whose name property contains the term "Duomo".

If you want to return all the points outside the polygon, you can set the inside property to false.