BoxLang 🚀 A New JVM Dynamic Language Learn More...
|:------------------------------------------------------: |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive |
| :----------------------------: |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com
Add native support for the powerful and lightweight Meilisearch search engine in your BoxLang application.
Meilisearch is a lightning-fast, open-source search engine that delivers instant search results with typo tolerance, filters, facets, and more. It handles millions of documents with ease while maintaining sub-50ms response times.
Key Features:
This module provides a fluent, BoxLang-native interface to the Meilisearch HTTP API. It simplifies integration and makes building search functionality a breeze.
Current Features:
Coming Soon:
Install via CommandBox:
box install bx-meilisearch
You can configure the Meilisearch API connection via environment variables:
export MEILISEARCH_URL=http://localhost:7700
export MEILISEARCH_MASTER_KEY=your-master-key
Or configure bx-meilisearch via boxlang.json:
// boxlang.json
"modules": {
"meilisearch": {
"enabled": true,
"settings": {
// Meilisearch instance URL (default: http://localhost:7700)
"url" : getSystemSetting( "MEILISEARCH_URL", "http://localhost:7700" ),
// Master or API key used for Authorization header
"masterKey" : getSystemSetting( "MEILISEARCH_MASTER_KEY", "changeMe" ),
// Optional callback invoked before each HTTP request is sent.
// Signature: ( httpResult, httpClient ) => {}
"onRequestStart" : null,
// Optional callback invoked after each HTTP request completes successfully.
// Signature: ( httpResult ) => {}
"onResponseCompletion": null
}
}
}
List all indexes with pagination and filtering options.
var result = meilisearch()
.indexes()
.list();
🔗 Meilisearch: List All Indexes
Swap two indexes for zero-downtime deployments.
meilisearch()
.indexes()
.swap( [ "books", "books_staging" ] );
Get database and index statistics including document counts and sizes.
var result = meilisearch()
.indexes()
.stats();
Retrieve a single index by its unique identifier.
var result = meilisearch()
.index( "books" )
.get();
Create a new index with an optional primary key.
// Create with auto-generated primary key
meilisearch()
.index( "books" )
.create();
// Create with specific primary key
meilisearch()
.index( "books" )
.create( "id" );
🔗 Meilisearch: Create an Index
Get index statistics.
var result = meilisearch()
.index( "books" )
.stats();
🔗 Meilisearch: Get stats of an index
Compact an index to reduce database fragmentation.
var result = meilisearch()
.index( "books" )
.compact();
🔗 Meilisearch: Compact an Index
Permanently delete an index and all its documents.
meilisearch()
.index( "books" )
.delete();
🔗 Meilisearch: Delete an Index
Add or replace documents in an index. Replaces existing documents with the same primary key.
var task = meilisearch()
.index( "books" )
.documents()
.add([
{ id: 1, title: "BoxLang for Beginners", author: "Jane Doe" },
{ id: 2, title: "Advanced BoxLang", author: "John Smith" }
])
.orReplace();
// Returns a Task object - use task.getStatus() to check progress
// task.getType() == "documentAdditionOrUpdate"
🔗 Meilisearch: Add or Replace Documents
Add or update documents in an index. Updates existing documents instead of replacing them entirely.
var task = meilisearch()
.index( "books" )
.documents()
.add([
{ id: 1, title: "BoxLang for Beginners - Updated Edition", author: "Jane Doe" },
{ id: 3, title: "BoxLang Cookbook", author: "New Author" }
])
.orUpdate();
// Returns a Task object - use task.getStatus() to check progress
// task.getType() == "documentAdditionOrUpdate"
🔗 Meilisearch: Add or Update Documents
Delete all documents from an index.
var task = meilisearch()
.index( "books" )
.documents()
.deleteAll();
// Returns a Task object - use task.getStatus() to check progress
// task.getType() == "documentDeletion"
🔗 Meilisearch: Delete All Documents
Retrieve documents from an index with optional filtering.
var result = meilisearch()
.index( "books" )
.documents()
.get({ offset: 0, limit: 20 });
Retrieve a specific document by its ID.
var result = meilisearch()
.index( "books" )
.document( "1" )
.get();
🔗 Meilisearch: Get One Document
Delete a specific document by its ID.
var task = meilisearch()
.index( "books" )
.document( "1" )
.delete();
// Returns a Task object
🔗 Meilisearch: Delete One Document
The Search DSL provides a fluent interface for querying documents in an index. It supports both POST (default) and GET request methods.
Search for documents using a query string.
var result = meilisearch()
.index( "books" )
.search( "tolkien" )
.send();
// Returns: {
// hits: [ { id: 1, title: "The Hobbit", ... }, ... ],
// query: "tolkien",
// processingTimeMs: 1,
// estimatedTotalHits: 2,
// ...
// }
🔗 Meilisearch: Search Documents
Pass initial parameters as the second argument to search().
var result = meilisearch()
.index( "books" )
.search( "tolkien", { limit: 5, offset: 0 } )
.send();
🔗 Meilisearch: Search Parameters
Chain parameter methods for a readable, builder-style interface.
var result = meilisearch()
.index( "books" )
.search( "tolkien" )
.filter( "genres = fantasy" )
.limit( 5 )
.offset( 0 )
.attributesToRetrieve( "title,author" )
.send();
Any Meilisearch search parameter can be used as a method call. The method name becomes the parameter name, and the method value becomes the parameter value.
Common parameters:
filter - Filter results using Meilisearch filter expressionslimit - Maximum number of results to returnoffset - Number of results to skip (for pagination)attributesToRetrieve - Comma-separated list of fields
to returnsort - Sort order (e.g., "price:asc")facets - Facets to compute🔗 Meilisearch: Search Parameters
Use sendWithGet() instead of send() to make
a GET request instead of POST.
var result = meilisearch()
.index( "books" )
.search( "tolkien" )
.limit( 10 )
.sendWithGet();
🔗 Meilisearch: Search with GET
The Facets API allows you to search for facet values using AI-powered prefix search and typo tolerance.
Note: This endpoint requires attributes to be added
to filterableAttributes in index settings first.
Search for facet values within a given facet.
// Search for facet values
var result = meilisearch()
.index( "books" )
.facetSearch( "genre", { facetQuery: "fiction" } )
.send();
// With additional parameters
var result = meilisearch()
.index( "books" )
.facetSearch( "genre", {
facetQuery: "fiction",
q: "fantasy",
filter: "rating > 3",
matchingStrategy: "all"
})
.send();
// Returns: {
// facetHits: [
// { value: "fiction", count: 7 }
// ],
// facetQuery: "fiction",
// processingTimeMs: 0
// }
List all API keys with optional pagination.
var result = meilisearch()
.keys()
.list();
// With pagination
var result = meilisearch()
.keys()
.list( { offset: 0, limit: 10 } );
Retrieve a single API key by its UID or key value.
var result = meilisearch()
.keys()
.get( "abc123" );
Update an existing API key's name or description.
meilisearch()
.keys()
.update( "abc123", { name: "Updated Key Name" } );
Permanently delete an API key.
meilisearch()
.keys()
.delete( "abc123" );
Retrieve the complete settings configuration for an index.
var result = meilisearch()
.index( "books" )
.settings()
.list();
Update index settings including ranking rules, searchable attributes, and more.
meilisearch()
.index( "books" )
.settings()
.update( {
"searchableAttributes": [ "title", "description", "author" ],
"filterableAttributes": [ "genre", "year" ],
"sortableAttributes": [ "year", "price" ],
"rankingRules": [
"words",
"typo",
"proximity",
"attribute",
"sort",
"exactness"
],
"stopWords": [ "the", "a", "an" ],
"synonyms": {
"computer": [ "pc", "laptop", "desktop" ]
}
} );
🔗 Meilisearch: Update Settings
Reset all index settings to their default values.
meilisearch()
.index( "books" )
.settings()
.reset();
List all asynchronous tasks with filtering and pagination options.
var result = meilisearch()
.tasks()
.list();
// With filters
var result = meilisearch()
.tasks()
.list( {
limit: 20,
statuses: "enqueued,processing",
types: "indexCreation,indexUpdate"
} );
Retrieve a single task by its unique identifier.
var result = meilisearch()
.tasks()
.get( "123" );
Cancel enqueued or processing tasks.
// Cancel specific tasks by UID
meilisearch()
.tasks()
.cancel( { uids: [ "1", "5", "7" ] } );
// Cancel tasks by status
meilisearch()
.tasks()
.cancel( { statuses: "enqueued" } );
Delete tasks matching specific criteria.
// Delete specific tasks by UID
meilisearch()
.tasks()
.delete( { uids: [ "1", "5" ] } );
// Delete tasks by status
meilisearch()
.tasks()
.delete( { statuses: "canceled" } );
// Delete completed tasks older than a date
meilisearch()
.tasks()
.delete( {
statuses: "succeeded,failed",
beforeEnqueuedAt: "2024-01-01T00:00: 00Z"
} );
The Batches API allows you to monitor how Meilisearch groups and processes asynchronous operations. Batches show the progress of grouped tasks.
List all batches with filtering and pagination options.
var result = meilisearch()
.batches()
.list();
// With filters
var result = meilisearch()
.batches()
.list({
limit: 10,
from: 0,
reverse: false
});
// Returns: {
// results: [
// {
// uid: 2,
// progress: null,
// details: { receivedDocuments: 6, indexedDocuments: 6 },
// stats: { totalNbTasks: 1, status: { succeeded: 1 } },
// duration: "PT0.110083S",
// startedAt: "2024-12-10T15:49: 04.995321Z",
// finishedAt: "2024-12-10T15:49: 05.105404Z",
// batchStrategy: "batched all enqueued tasks"
// }
// ],
// total: 3,
// limit: 1,
// from: 2
// }
Retrieve a single batch by its unique identifier.
var result = meilisearch()
.batches()
.get( "0" );
// Returns: {
// uid: 0,
// progress: { steps: [...], percentage: 32.8471 },
// details: { receivedDocuments: 6, indexedDocuments: 6 },
// stats: { totalNbTasks: 1, status: { succeeded: 1 } },
// duration: "PT0.250518S",
// startedAt: "2024-12-10T15:20: 30.18182Z",
// finishedAt: "2024-12-10T15:20: 30.432338Z",
// batchStrategy: "batched all enqueued tasks"
// }
The Webhooks API allows you to trigger automatic workflows when Meilisearch finishes processing tasks. When a task completes, Meilisearch sends the task object to all configured webhooks.
Note: You can create up to 20 webhooks. Having multiple webhooks active at the same time may negatively impact performance.
List all configured webhooks.
var result = meilisearch()
.webhooks()
.list();
// Returns: {
// results: [
// {
// uuid: "627ea538-733d-4545-8d2d-03526eb381ce",
// url: "https://example.com/webhook",
// headers: { authorization: "REDACTED" },
// isEditable: true
// }
// ]
// }
Create a new webhook to receive task completion notifications.
var result = meilisearch()
.webhooks()
.create({
url: "https://example.com/webhook",
headers: {
authorization: "Bearer SECRET_KEY",
referer: "https://example.com"
}
});
// Returns: {
// uuid: "627ea538-733d-4545-8d2d-03526eb381ce",
// url: "https://example.com/webhook",
// headers: {
// authorization: "Bearer SECRET_KEY",
// referer: "https://example.com"
// },
// isEditable: true
// }
Retrieve a single webhook by its UUID.
var result = meilisearch()
.webhooks()
.webhook( "WEBHOOK_UUID" )
.get();
Update a webhook's configuration. To remove a field, set its value to null.
var result = meilisearch()
.webhooks()
.webhook( "WEBHOOK_UUID" )
.update({
headers: {
referer: null // Remove this header
}
});
// Returns: {
// uuid: "627ea538-733d-4545-8d2d-03526eb381ce",
// url: "https://example.com/webhook",
// headers: {
// authorization: "Bearer SECRET_KEY"
// },
// isEditable: true
// }
Delete a webhook to stop receiving task completion notifications.
meilisearch()
.webhooks()
.webhook( "WEBHOOK_UUID" )
.delete();
// Returns: 204 No Content
Every asynchronous operation in Meilisearch (index creation, document updates, index swaps, etc.) returns a Task object. This object provides methods to track the operation's progress and wait for completion.
Meilisearch operations are asynchronous - when you create an index or
add documents, Meilisearch creates a Task to track that
operation while it continues in the background. You use the Task
object to:
// Create an index - returns a Task object immediately
var task = meilisearch()
.index( "books" )
.create();
// Check initial status
print( "Task Status: " & task.getStatus() ); // "enqueued"
print( "Task Type: " & task.getType() ); // "indexCreation"
print( "Task UID: " & task.getTaskUid() ); // "123"
// Wait for the task to complete (polls every second, by default)
var completedTask = task.waitForCompletion();
// Check final status
if ( completedTask.getStatus() == "succeeded" ) {
print( "Index created successfully!" );
} else if ( completedTask.getStatus() == "failed" ) {
print( "Failed: " & completedTask.getError().message );
}
Get the current status of the task.
var task = meilisearch()
.index( "books" )
.create();
print( task.getStatus() ); // "enqueued", "processing", "succeeded", "failed", or "canceled"
Possible values:
enqueued - Task is in the queue, waiting to be processedprocessing - Task is currently being processedsucceeded - Task completed successfullyfailed - Task failed (check getError() for details)canceled - Task was canceledGet the type of operation this task represents.
var task = meilisearch()
.index( "books" )
.documents()
.add([ { id: 1, title: "Book" } ])
.orReplace();
print( task.getType() ); // "documentAdditionOrUpdate"
Common types:
indexCreation - Creating a new indexindexUpdate - Updating an indexindexDeletion - Deleting an indexdocumentAdditionOrUpdate - Adding or updating documentsdocumentDeletion - Deleting documentsindexSwap - Swapping two indexessettingsUpdate - Updating index settingsConvert the Task object to a plain struct with all task data.
var task = meilisearch()
.index( "books" )
.create();
var taskData = task.toStruct();
// Returns: {
// taskUid: "123",
// indexUid: "books",
// status: "succeeded",
// type: "indexCreation",
// enqueuedAt: "2024-01-15T10:30: 00.000Z",
// startedAt: "2024-01-15T10:30: 01.000Z",
// finishedAt: "2024-01-15T10:30: 02.000Z",
// duration: "1s",
// details: { ... }
// }
Wait for the task to complete by polling at regular intervals.
var task = meilisearch()
.index( "books" )
.documents()
.add([
{ id: 1, title: "Book 1" },
{ id: 2, title: "Book 2" }
])
.orReplace();
// Wait up to 30 seconds, polling every 2 seconds
var completedTask = task.waitForCompletion( 2000, 30000 );
if ( completedTask.getStatus() == "succeeded" ) {
print( "Documents added successfully!" );
print( "Documents processed: " & completedTask.getDetails().receivedDocuments );
}
Parameters:
interval (integer) - Number of milliseconds to wait
between polls (default: 1000)timeout (integer) - Maximum time to wait for task
completion in milliseconds (default: 30000)Returns: A new Task object with the final task status
Note: The original Task object is not modified;
waitForCompletion() returns a new Task instance with
updated data.
var task = meilisearch().index( "books" ).create();
// Get basic info
task.getTaskUid(); // Unique task identifier
task.getIndexUid(); // Index this task operates on
task.getEnqueuedAt(); // When task was queued (ISO timestamp)
task.getStartedAt(); // When processing started
task.getFinishedAt(); // When processing finished
task.getDuration(); // How long processing took
// Get detailed info
task.getDetails(); // Task-specific details (varies by type)
task.getError(); // Error info if task failed
task.getCanceledBy(); // UID of task that canceled this one (if any)
// Check completion status
task.isComplete(); // Returns true if status is "succeeded", "failed", or "canceled"
List all available experimental features and their current status.
var result = meilisearch()
.experimentalFeatures()
.list();
🔗 Meilisearch: Get Experimental Features
Retrieve the status of a specific experimental feature.
var result = meilisearch()
.experimentalFeatures()
.get( "metrics" );
🔗 Meilisearch: Get One Experimental Feature
Enable or disable a specific experimental feature.
// Enable
meilisearch()
.experimentalFeatures()
.set( "metrics", true );
// Disable
meilisearch()
.experimentalFeatures()
.set( "metrics", false );
🔗 Meilisearch: Update Experimental Features
Enable or disable multiple experimental features at once.
meilisearch()
.experimentalFeatures()
.setAll( {
"metrics": true,
"exportPayer": false,
"logs": true
} );
🔗 Meilisearch: Update Experimental Features
Create a snapshot of the Meilisearch instance for backup purposes.
var result = meilisearch()
.snapshots()
.create();
🔗 Meilisearch: Create Snapshot
The Network API allows you to create a network of Meilisearch instances for federated search and horizontal database partitioning strategies like sharding.
Note: This is an experimental feature. Enable it first using the experimental features endpoint.
Retrieve the current network configuration including self instance name, sharding status, and remote instances.
var result = meilisearch()
.network()
.get();
// Returns: {
// self: "ms-00",
// sharding: false,
// remotes: {
// "ms-00": {
// url: "http://ms-1235.example.meilisearch.io",
// searchApiKey: "Ecd1SDDi4pqdJD6qYLxD3y7VZAEb4d9j6LJgt4d6xas"
// }
// }
// }
Update the network configuration. Updates are partial - only provide the fields you want to update.
meilisearch()
.network()
.update({
self: "ms-00",
sharding: true,
remotes: {
"ms-00": {
url: "http://localhost:7700",
searchApiKey: "masterKey",
writeApiKey: "masterKey"
},
"ms-01": {
url: "http://remote-instance:7700",
searchApiKey: "remoteSearchKey",
writeApiKey: "remoteWriteKey"
}
}
});
The Similar Documents API uses AI-powered search to find documents similar to a specific document. This requires the document to have vector embeddings generated by a configured embedder.
Note: This endpoint requires an embedder to be configured in the index settings first.
Find documents similar to a target document using POST or GET requests.
// Using POST (recommended)
var result = meilisearch()
.index( "books" )
.document( "123" )
.similar({ embedder: "default" })
.send();
// Using GET
var result = meilisearch()
.index( "books" )
.document( "123" )
.similar({ embedder: "default" })
.sendGet();
// With additional parameters
var result = meilisearch()
.index( "books" )
.document( "123" )
.similar({
embedder: "default",
limit: 10,
filter: "genre = fiction",
showRankingScore: true
})
.send();
// Returns: {
// hits: [
// { id: "456", title: "Similar Book 1" },
// { id: "789", title: "Similar Book 2" }
// ],
// id: "123",
// processingTimeMs: 5,
// limit: 10,
// offset: 0,
// estimatedTotalHits: 2
// }
🔗 Meilisearch: Similar Documents
Check if the Meilisearch instance is available and responding.
var result = meilisearch()
.health();
// Returns: { "status": "available" }
Retrieve the version information of the Meilisearch instance.
var result = meilisearch()
.version();
// Returns: { "commitSha": "...", "commitDate": "...", "pkgVersion": "1.x.x" }
Bx-Meilisearch+ is a premium BoxLang module available exclusively to BoxLang+ members.
BoxLang+ provides:
Learn more about BoxLang+ and join today!
BoxLang is a professional open-source project and it is completely funded by the community and Ortus Solutions, Corp. Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: https://patreon.com/ortussolutions
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
$
box install bx-meilisearch