From 600bc0216c963ab943bd59283f8bb32807b05c97 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:08:33 +0300 Subject: [PATCH 001/107] update endpoints --- integration/rest.md | 1255 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 1104 insertions(+), 151 deletions(-) diff --git a/integration/rest.md b/integration/rest.md index 72154678..8690ea58 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -5,370 +5,1323 @@ description: "Rest API detailed doc" parent: "Integration" --- -# Rest API +# FalkorDB Browser REST API + +REST API for FalkorDB Browser - Graph Database Management Interface + +**Version:** 1.4.6 + +**Base URL:** Your FalkorDB Browser instance URL + +**Authentication:** Bearer Token (JWT) ## Table of Contents -- [Login - GET /api/auth/providers](#login---get-apiauthproviders) -- [Logout - POST /api/auth/signout](#logout---post-apiauthsignout) -- [Set Configuration Value - POST /api/config](#set-configuration-value---post-apiconfig) -- [Get Configuration Value - GET /api/config](#get-configuration-value---get-apiconfig) -- [Create New User - POST /api/user](#create-new-user---post-apiuser) -- [Delete User - POST /api/user](#delete-user---post-apiuser) -- [Get All Users - GET /api/user](#get-all-users---get-apiuser) -- [Modify a User - PATCH /api/user/{userName}](#modify-a-user---patch-apiuserusername) -- [Create a Graph & Run A Query - GET /api/graph/{graphName}](#create-a-graph--run-a-query---get-apigraphgraphname) -- [Delete a Graph - DELETE /api/graph/{graphName}](#delete-a-graph---delete-apigraphgraphname) -- [Get All Graphs - GET /api/graph](#get-all-graphs---get-apigraph) -- [Duplicate a Graph - POST /api/graph/{destinationGraphName}](#duplicate-a-graph---post-apigraphdestinationgraphname) -- [Create New Schema & Run A Query - GET /api/graph/{schemaName}](#create-new-schema--run-a-query---get-apigraphschemaname) -- [Delete a Schema - DELETE /api/graph/{schemaName}](#delete-a-schema---delete-apigraphschemaname) +### Authentication +- [User login - POST /api/auth/login](#user-login---post-apiauthlogin) + +### Status +- [Check FalkorDB connection status - GET /api/status](#check-falkordb-connection-status---get-apistatus) + +### Graph Management +- [List all graphs - GET /api/graph](#list-all-graphs---get-apigraph) +- [Execute graph query - GET /api/graph/{graph}](#execute-graph-query---get-apigraphgraph) +- [Create or verify a graph - POST /api/graph/{graph}](#create-or-verify-a-graph---post-apigraphgraph) +- [Rename graph - PATCH /api/graph/{graph}](#rename-graph---patch-apigraphgraph) +- [Delete a graph - DELETE /api/graph/{graph}](#delete-a-graph---delete-apigraphgraph) +- [Get query execution plan - GET /api/graph/{graph}/explain](#get-query-execution-plan---get-apigraphgraphexplain) +- [Profile query execution - GET /api/graph/{graph}/profile](#profile-query-execution---get-apigraphgraphprofile) +- [Get graph information - GET /api/graph/{graph}/info](#get-graph-information---get-apigraphgraphinfo) +- [Get graph element counts - GET /api/graph/{graph}/count](#get-graph-element-counts---get-apigraphgraphcount) +- [Export graph data - GET /api/graph/{graph}/export](#export-graph-data---get-apigraphgraphexport) +- [Duplicate a graph - PATCH /api/graph/{graph}/duplicate](#duplicate-a-graph---patch-apigraphgraphduplicate) +- [Get node information - GET /api/graph/{graph}/{node}](#get-node-information---get-apigraphgraphnode) +- [Delete node or relationship - DELETE /api/graph/{graph}/{node}](#delete-node-or-relationship---delete-apigraphgraphnode) +- [Add node label - POST /api/graph/{graph}/{node}/label](#add-node-label---post-apigraphgraphnodelabel) +- [Remove node label - DELETE /api/graph/{graph}/{node}/label](#remove-node-label---delete-apigraphgraphnodelabel) +- [Set node/relationship property - POST /api/graph/{graph}/{node}/{key}](#set-noderelationship-property---post-apigraphgraphnodekey) +- [Remove node/relationship property - DELETE /api/graph/{graph}/{node}/{key}](#remove-noderelationship-property---delete-apigraphgraphnodekey) + +### Configuration Management +- [Get all configuration values - GET /api/graph/config](#get-all-configuration-values---get-apigraphconfig) +- [Get specific configuration value - GET /api/graph/config/{config}](#get-specific-configuration-value---get-apigraphconfigconfig) +- [Set configuration value - POST /api/graph/config/{config}](#set-configuration-value---post-apigraphconfigconfig) + +### Schema Management +- [List all schemas - GET /api/schema](#list-all-schemas---get-apischema) +- [Get schema information - GET /api/schema/{schema}](#get-schema-information---get-apischemaschema) +- [Create new schema - POST /api/schema/{schema}](#create-new-schema---post-apischemaschema) +- [Rename schema - PATCH /api/schema/{schema}](#rename-schema---patch-apischemaschema) +- [Delete schema - DELETE /api/schema/{schema}](#delete-schema---delete-apischemaschema) +- [Get schema element counts - GET /api/schema/{schema}/count](#get-schema-element-counts---get-apischemaschemacount) +- [Duplicate schema - PATCH /api/schema/{schema}/duplicate](#duplicate-schema---patch-apischemaschemaduplicat) +- [Create node or relationship in schema - POST /api/schema/{schema}/new](#create-node-or-relationship-in-schema---post-apischemaschemanew) +- [Create node in schema - POST /api/schema/{schema}/nodes](#create-node-in-schema---post-apischemaschemanode) +- [Create relationship in schema - POST /api/schema/{schema}/relationships](#create-relationship-in-schema---post-apischemaschemarelationships) +- [Delete node from schema - DELETE /api/schema/{schema}/{nodeId}](#delete-node-from-schema---delete-apischemaschemanodeid) +- [Delete relationship from schema - DELETE /api/schema/{schema}/{relationshipId}](#delete-relationship-from-schema---delete-apischemaschemarelationshipid) +- [Add label to node - POST /api/schema/{schema}/{node}/label](#add-label-to-node---post-apischemaschemanode/label) +- [Remove label from node - DELETE /api/schema/{schema}/{node}/label](#remove-label-from-node---delete-apischemaschemanode/label) +- [Add/Update attribute to node - PATCH /api/schema/{schema}/{nodeId}/{key}](#addupdate-attribute-to-node---patch-apischemaschemanodeidkey) +- [Remove attribute from node - DELETE /api/schema/{schema}/{nodeId}/{key}](#remove-attribute-from-node---delete-apischemaschemanodeidkey) +- [Add/Update attribute to relationship - PATCH /api/schema/{schema}/{relationshipId}/{key}](#addupdate-attribute-to-relationship---patch-apischemaschemarelationshipidkey) +- [Remove attribute from relationship - DELETE /api/schema/{schema}/{relationshipId}/{key}](#remove-attribute-from-relationship---delete-apischemaschemarelationshipidkey) + +### User Management +- [List all users - GET /api/user](#list-all-users---get-apiuser) +- [Create new user - POST /api/user](#create-new-user---post-apiuser) +- [Delete multiple users - DELETE /api/user](#delete-multiple-users---delete-apiuser) +- [Update user role - PATCH /api/user/{user}](#update-user-role---patch-apiuseruser) --- -### **Login** - `GET /api/auth/providers` +## Authentication -This endpoint retrieves information about authentication providers and their respective URLs for sign-in and callback. +All endpoints except `/api/auth/login` require authentication using a JWT bearer token in the Authorization header: +``` +Authorization: Bearer +``` + +### **User login** - `POST /api/auth/login` + +Authenticate user with username and password. + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `username`, `password` + +Example request: +```json +{ + "username": "default", + "password": "password" +} +``` #### Responses -- **200**: Successful authentication provider retrieval +- **200**: Login successful - Content-Type: `application/json` - Example response: ```json { - "credentials": { - "id": "credentials", - "name": "Credentials", - "type": "credentials", - "signinUrl": "http://localhost:3000/api/auth/signin/credentials", - "callbackUrl": "http://localhost:3000/api/auth/callback/credentials" + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "user": { + "username": "default", + "role": "Admin" } } ``` -### **Logout** - `POST /api/auth/signout` +- **400**: Bad request - missing username or password +- **401**: Invalid credentials +- **500**: Internal server error -This endpoint signs out a user, ending their authenticated session. +--- -#### Request Body +## Status -- Content-Type: `application/x-www-form-urlencoded` -- Example request: +### **Check FalkorDB connection status** - `GET /api/status` - ```json - { - "csrfToken": "insert csrfToken", - "callbackUrl": "/login", - "json": true - } - ``` +Returns the current connection status to the FalkorDB database. + +#### Headers +- `Authorization: Bearer ` (required) #### Responses -- **200**: Successful logout +- **200**: Database is online and accessible - Content-Type: `application/json` - Example response: ```json { - "url": "http://localhost:3000/api/auth/signout?csrf=true" + "status": "online" } ``` -### **Set Configuration Value** - `POST /api/config` +- **404**: Database is offline or not accessible +- **500**: Internal server error + +--- -This endpoint sets a configuration value for `MAX_QUEUED_QUERIES`. +## Graph Management -#### Parameters +### **List all graphs** - `GET /api/graph` -- `cookie` (header, required): Cookie header with session and auth tokens. -- `config` (query, required): The configuration name. -- `value` (query, required): The integer value to set. +Get a list of all graphs in the FalkorDB instance. + +#### Headers +- `Authorization: Bearer ` (required) #### Responses -- **200**: Successful configuration update +- **200**: List of graphs retrieved successfully - Content-Type: `application/json` - Example response: ```json { - "config": "OK" + "opts": [ + "social_network", + "product_catalog", + "user_interactions" + ] } ``` -### **Get Configuration Value** - `GET /api/config` +- **400**: Bad request +- **500**: Internal server error + +### **Execute graph query** - `GET /api/graph/{graph}` + +Execute a Cypher query on the specified graph (Server-Sent Events). -This endpoint retrieves the value for `MAX_QUEUED_QUERIES`. +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `graph` (path, required): Graph name to query + - Example: `social_network` +- `query` (query, required): Cypher query to execute + - Example: `MATCH (n) RETURN n LIMIT 10` +- `timeout` (query, required): Query timeout in milliseconds + - Example: `30000` + +#### Responses + +- **200**: Query executed successfully (Server-Sent Events stream) -- `cookie` (header, required): Cookie header with session and auth tokens. -- `config` (query, required): The name of the configuration to retrieve. +### **Create or verify a graph** - `POST /api/graph/{graph}` + +Create a new graph or verify that a graph exists. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name to create or verify #### Responses -- **200**: Successful configuration retrieval +- **200**: Graph created or verified successfully - Content-Type: `application/json` - Example response: ```json { - "config": [ - "MAX_QUEUED_QUERIES", - 25 - ] + "message": "Graph created successfully" } ``` -### **Create New User** - `POST /api/user` +- **400**: Bad request +- **500**: Internal server error -This endpoint creates a new user with specified credentials. +### **Rename graph** - `PATCH /api/graph/{graph}` -#### Request Body +Rename an existing graph to a new name. -- Content-Type: `application/json` -- Example request: +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): New graph name +- `sourceName` (query, required): Current graph name to rename + +#### Responses + +- **200**: Graph renamed successfully + - Content-Type: `application/json` + - Example response: ```json { - "username": "user", - "password": "Pass123@", - "role": "Read-Write" + "data": { + "result": "Graph renamed successfully" + } } ``` +- **400**: Bad request - graph already exists or missing sourceName +- **500**: Internal server error + +### **Delete a graph** - `DELETE /api/graph/{graph}` + +Delete a graph from the FalkorDB instance. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name to delete + #### Responses -- **201**: User created successfully +- **200**: Graph deleted successfully - Content-Type: `application/json` - Example response: ```json { - "message": "User created" + "message": "graph_name graph deleted" } ``` -### **Delete User** - `POST /api/user` +- **400**: Bad request +- **500**: Internal server error -This endpoint deletes a user based on their username and role. +### **Get query execution plan** - `GET /api/graph/{graph}/explain` -#### Request Body +Get the execution plan for a Cypher query without executing it. -- Content-Type: `application/json` -- Example request: +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `query` (query, required): Cypher query to explain + +#### Responses + +- **200**: Query execution plan returned successfully + +### **Profile query execution** - `GET /api/graph/{graph}/profile` + +Get detailed profiling information for a Cypher query. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `query` (query, required): Cypher query to profile + +#### Responses + +- **200**: Query profiling information returned successfully + +### **Get graph information** - `GET /api/graph/{graph}/info` + +Get specific information about a graph (functions, property keys, labels, or relationship types). + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `type` (query, required): Type of information to retrieve + - Options: `(function)`, `(property key)`, `(label)`, `(relationship type)` + - Example: `(label)` + +#### Responses + +- **200**: Graph information retrieved successfully + - Content-Type: `application/json` + - Example response: ```json { - "users": [ - { - "username": "userName", - "role": "Read-Write" - } - ] + "result": { + "data": [ + {"(label)": "Person"}, + {"(label)": "Company"} + ] + } } ``` +- **400**: Bad request - missing or invalid type parameter + +### **Get graph element counts** - `GET /api/graph/{graph}/count` + +Get the count of nodes and relationships in a graph. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name + #### Responses -- **200**: User deleted successfully +- **200**: Element counts retrieved successfully + +### **Export graph data** - `GET /api/graph/{graph}/export` + +Export graph data in various formats. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name + +#### Responses + +- **200**: Graph data exported successfully + +### **Duplicate a graph** - `PATCH /api/graph/{graph}/duplicate` + +Create a copy of an existing graph with a new name. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): New graph name for the duplicate +- `sourceName` (query, required): Source graph name to duplicate from + +#### Responses + +- **200**: Graph duplicated successfully - Content-Type: `application/json` - Example response: ```json { - "message": "User deleted" + "result": { + "status": "Graph duplicated successfully" + } } ``` -### **Get All Users** - `GET /api/user` +- **400**: Bad request - missing sourceName parameter +- **500**: Internal server error + +### **Get node information** - `GET /api/graph/{graph}/{node}` + +Get detailed information about a specific node. -This endpoint retrieves a list of all users. +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node ID #### Responses -- **200**: List of users retrieved successfully +- **200**: Node information retrieved successfully - Content-Type: `application/json` - Example response: ```json { - "result": [ - { - "username": "default", - "role": "Admin", - "checked": false - } - ] + "result": { + "data": [ + { + "node": { + "id": 1, + "labels": ["Person"], + "properties": { + "name": "John Doe", + "age": 30 + } + }, + "relationships": [] + } + ] + } } ``` -### **Modify A User** - `PATCH /api/user/{userName}` +- **400**: Bad request +- **500**: Internal server error + +### **Delete node or relationship** - `DELETE /api/graph/{graph}/{node}` -This endpoint updates the role of a specific user. +Delete a node or relationship from the graph. + +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node or relationship ID + +#### Request Body -- `cookie` (header, required): Cookie header with session and auth tokens. -- `userName` (path, required): The username of the user to modify. -- `role` (query, required): The new role to assign to the user (`Admin`, `Read-Only`, `Read-Write`). +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": true +} +``` + +- `type`: `true` to delete a node, `false` to delete a relationship #### Responses -- **200**: User updated successfully +- **200**: Node or relationship deleted successfully - Content-Type: `application/json` - Example response: ```json { - "message": "User role updated" + "message": "Node deleted successfully" } ``` -### **Create A Graph & Run A Query** - `GET /api/graph/{graphName}` +- **400**: Bad request - missing type parameter +- **500**: Internal server error + +### **Add node label** - `POST /api/graph/{graph}/{node}/label` + +Add a label to a specific node. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node ID + +#### Request Body + +- Content-Type: `application/json` + +Example request: +```json +{ + "label": "your_label" +} +``` + +#### Responses + +- **200**: Label added successfully + +### **Remove node label** - `DELETE /api/graph/{graph}/{node}/label` + +Remove a label from a specific node. + +#### Headers +- `Authorization: Bearer ` (required) -This endpoint creates a graph and runs a query. +#### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node ID + +#### Request Body + +- Content-Type: `application/json` + +Example request: +```json +{ + "label": "your_label" +} +``` + +#### Responses + +- **200**: Label removed successfully + +### **Set node/relationship property** - `POST /api/graph/{graph}/{node}/{key}` + +Set a property value on a node or relationship. + +**IMPORTANT:** Use `type=true` for nodes, `type=false` for relationships. + +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node or relationship ID +- `key` (path, required): Property key name + +#### Request Body -- `cookie` (header, required): Cookie header with session and auth tokens. -- `graphName` (path, required): The name of the graph to be created. -- `query` (query, required): The query to run, such as `RETURN 1`. +- Content-Type: `application/json` +- Required fields: `value`, `type` + +Example request: +```json +{ + "value": "your_property_value", + "type": true +} +``` + +- `value`: Property value to set +- `type`: `true` for nodes, `false` for relationships #### Responses -- **200**: Graph created and query executed +- **200**: Property set successfully + +### **Remove node/relationship property** - `DELETE /api/graph/{graph}/{node}/{key}` + +Remove a property from a node or relationship. + +**IMPORTANT:** Use `type=true` for nodes, `type=false` for relationships. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `graph` (path, required): Graph name +- `node` (path, required): Node or relationship ID +- `key` (path, required): Property key name + +#### Request Body + +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": true +} +``` + +- `type`: `true` for nodes, `false` for relationships + +#### Responses + +- **200**: Property removed successfully + +--- + +## Configuration Management + +### **Get all configuration values** - `GET /api/graph/config` + +Get all FalkorDB configuration parameters and their values. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Responses + +- **200**: Configuration values retrieved successfully - Content-Type: `application/json` - Example response: ```json { - "result": { - "metadata": [ - "Nodes created: 40", - "Relationships created: 20", - "Cached execution: 1", - "Query internal execution time: 0.201420 milliseconds" - ], - "data": [ - { - "queryData": "exampleData" - } - ] + "configs": { + "MAX_INFO_QUERIES": 700, + "CMD_INFO": "server", + "TIMEOUT": 1000 } } ``` -### **Delete A Graph** - `DELETE /api/graph/{graphName}` +- **400**: Bad request +- **500**: Internal server error -This endpoint deletes a specified graph. +### **Get specific configuration value** - `GET /api/graph/config/{config}` -#### Parameters +Get the value of a specific configuration parameter. + +#### Headers +- `Authorization: Bearer ` (required) -- `cookie` (header, required): Cookie header with session and auth tokens. -- `graphName` (path, required): The name of the graph to be deleted. +#### Parameters +- `config` (path, required): Configuration parameter name + - Example: `MAX_INFO_QUERIES` #### Responses -- **200**: Graph deleted successfully +- **200**: Configuration value retrieved successfully - Content-Type: `application/json` - Example response: ```json { - "message": "GraphName graph deleted" + "config": 700 } ``` -### **Get All Graphs** - `GET /api/graph` +- **400**: Bad request +- **500**: Internal server error + +### **Set configuration value** - `POST /api/graph/config/{config}` + +Set the value of a specific configuration parameter. -This endpoint retrieves a list of all graphs. +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `config` (path, required): Configuration parameter name + - Example: `MAX_INFO_QUERIES` +- `value` (query, required): Configuration value to set (numeric values will be parsed as integers except for CMD_INFO) + - Example: `700` #### Responses -- **200**: List of graphs retrieved successfully +- **200**: Configuration value set successfully - Content-Type: `application/json` - Example response: ```json { - "result": [ - "graphName" - ] + "config": "OK" } ``` -### **Duplicate A Graph** - `POST /api/graph/{destinationGraphName}` +- **400**: Bad request - missing value or invalid value +- **500**: Internal server error -This endpoint duplicates a graph from source to destination. +--- + +## Schema Management + +### **List all schemas** - `GET /api/schema` + +Get a list of all schemas in the FalkorDB instance. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Responses + +- **200**: List of schemas retrieved successfully + +### **Get schema information** - `GET /api/schema/{schema}` + +Get detailed information about a specific schema. + +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `schema` (path, required): Schema name + +#### Responses + +- **200**: Schema information retrieved successfully + +### **Create new schema** - `POST /api/schema/{schema}` + +Create a new schema with the specified name. -- `destinationGraphName` (path, required): The name of the destination graph. -- `sourceName` (query, required): The name of the source graph to duplicate. +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name to create #### Responses -- **200**: Graph duplicated successfully +- **201**: Schema created successfully + +### **Rename schema** - `PATCH /api/schema/{schema}` + +Rename an existing schema to a new name. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): New schema name +- `sourceName` (query, required): Current schema name to rename + +#### Responses + +- **200**: Schema renamed successfully - Content-Type: `application/json` - Example response: ```json { - "success": "OK" + "data": { + "result": "Schema renamed successfully" + } } ``` -### **Create New Schema & Run A Query** - `GET /api/graph/{schemaName}` +- **400**: Bad request - schema already exists or missing sourceName +- **500**: Internal server error + +### **Delete schema** - `DELETE /api/schema/{schema}` + +Delete a schema and all its data permanently. -This endpoint creates a new schema and runs a query. +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `schema` (path, required): Schema name to delete -- `schemaName` (path, required): The name of the schema to create. -- `query` (query, required): The query to execute. +#### Responses + +- **200**: Schema deleted successfully + +### **Get schema element counts** - `GET /api/schema/{schema}/count` + +Get the count of nodes and relationships in a schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name + +#### Responses + +- **200**: Schema element counts retrieved successfully + +### **Duplicate schema** - `PATCH /api/schema/{schema}/duplicate` + +Create a copy of an existing schema with a new name, preserving all data and structure. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): New schema name for the duplicate +- `sourceName` (query, required): Source schema name to duplicate from #### Responses -- **200**: Schema created and query executed +- **200**: Schema duplicated successfully - Content-Type: `application/json` - Example response: ```json { "result": { - "metadata": [ - "Cached execution: 0", - "Query internal execution time: 0.153307 milliseconds" - ], - "data": [ - { - "1": 1 - } - ] + "status": "Schema duplicated successfully" } } ``` -### **Delete A Schema** - `DELETE /api/graph/{schemaName}` +- **400**: Bad request - missing sourceName parameter +- **500**: Internal server error + +### **Create node or relationship in schema** - `POST /api/schema/{schema}/new` -This endpoint deletes a specified schema. +The actual backend endpoint for creating nodes and relationships. Use `type=true` for nodes, `type=false` for relationships. + +#### Headers +- `Authorization: Bearer ` (required) #### Parameters +- `schema` (path, required): Schema name -- `schemaName` (path, required): The name of the schema to delete. +#### Request Body + +- Content-Type: `application/json` +- Required fields: `type`, `label`, `attributes` + +Example request for node creation: +```json +{ + "type": true, + "label": ["Person", "User"], + "attributes": [ + ["name", ["STRING", "", "false", "true"]], + ["age", ["INTEGER", "0", "false", "false"]] + ] +} +``` + +Example request for relationship creation: +```json +{ + "type": false, + "label": ["KNOWS"], + "attributes": [ + ["since", ["STRING", "2024", "false", "false"]] + ], + "selectedNodes": [{"id": 1}, {"id": 2}] +} +``` + +- `type`: `true` for node creation, `false` for relationship creation +- `label`: For nodes: Multiple labels supported (e.g., `["Person", "User"]`). For relationships: Relationship type (only first label used, e.g., `["KNOWS"]`) +- `attributes`: Attribute definitions: `[[key, [type, default, unique, required]], ...]` +- `selectedNodes`: Required for relationship creation only. Source and target nodes (exactly 2 nodes) #### Responses -- **200**: Schema deleted successfully +- **200**: Node or relationship created successfully + +### **Create node in schema** - `POST /api/schema/{schema}/nodes` + +Create a new node in the specified schema. Multiple labels are supported and will be joined with colons (e.g., `:Person:User`). This endpoint maps to `/api/schema/{schema}/new` with `type=true`. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `type`, `label`, `attributes` + +Example request: +```json +{ + "type": true, + "label": ["Person", "User"], + "attributes": [ + ["name", ["STRING", "", "false", "true"]], + ["age", ["INTEGER", "0", "false", "false"]] + ] +} +``` + +- `type`: Must be `true` for node creation +- `label`: Labels for the node (multiple labels supported) +- `attributes`: Attribute definitions: `[[key, [type, default, unique, required]], ...]` + +#### Responses + +- **200**: Node created successfully + +### **Create relationship in schema** - `POST /api/schema/{schema}/relationships` + +Create a new relationship between two nodes in the specified schema. Only the first label in the array is used as the relationship type. This endpoint maps to `/api/schema/{schema}/new` with `type=false`. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `type`, `label`, `attributes`, `selectedNodes` + +Example request: +```json +{ + "type": false, + "label": ["KNOWS"], + "attributes": [ + ["since", ["STRING", "2024", "false", "false"]] + ], + "selectedNodes": [{"id": 1}, {"id": 2}] +} +``` + +- `type`: Must be `false` for relationship creation +- `label`: Relationship type (only first label used) +- `attributes`: Attribute definitions: `[[key, [type, default, unique, required]], ...]` +- `selectedNodes`: Source and target nodes for the relationship (exactly 2 nodes) + +#### Responses + +- **200**: Relationship created successfully + +### **Delete node from schema** - `DELETE /api/schema/{schema}/{nodeId}` + +Delete a specific node from the schema by ID. Set `type=true` for node deletion. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name +- `nodeId` (path, required): Node ID to delete + +#### Request Body + +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": true +} +``` + +- `type`: Must be `true` for node deletion + +#### Responses + +- **200**: Node deleted successfully + +### **Delete relationship from schema** - `DELETE /api/schema/{schema}/{relationshipId}` + +Delete a specific relationship from the schema by ID. Set `type=false` for relationship deletion. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name +- `relationshipId` (path, required): Relationship ID to delete + +#### Request Body + +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": false +} +``` + +- `type`: Must be `false` for relationship deletion + +#### Responses + +- **200**: Relationship deleted successfully + +### **Add label to node** - `POST /api/schema/{schema}/{node}/label` + +Add a new label to an existing node in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name +- `node` (path, required): Node ID + +#### Request Body + +- Content-Type: `application/json` +- Required field: `label` + +Example request: +```json +{ + "label": "your_label" +} +``` + +#### Responses + +- **200**: Label added successfully + +### **Remove label from node** - `DELETE /api/schema/{schema}/{node}/label` + +Remove a specific label from an existing node in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name +- `node` (path, required): Node ID + +#### Request Body + +- Content-Type: `application/json` +- Required field: `label` + +Example request: +```json +{ + "label": "your_label" +} +``` + +#### Responses + +- **200**: Label removed successfully + +### **Add/Update attribute to node** - `PATCH /api/schema/{schema}/{nodeId}/{key}` + +Add a new attribute or update an existing attribute on a node in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name (example: `test`) +- `nodeId` (path, required): Node ID (example: `2`) +- `key` (path, required): Attribute key to add/update (example: `attribute_key`) + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `type`, `attribute` + +Example request: +```json +{ + "type": true, + "attribute": ["STRING", "your_description", "false", "true"] +} +``` + +- `type`: Must be `true` for node attributes +- `attribute`: Attribute configuration `[type, default, unique, required]` + +#### Responses + +- **200**: Attribute added/updated successfully + +### **Remove attribute from node** - `DELETE /api/schema/{schema}/{nodeId}/{key}` + +Remove a specific attribute from a node in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name (example: `test`) +- `nodeId` (path, required): Node ID (example: `2`) +- `key` (path, required): Attribute key to remove (example: `attribute_key`) + +#### Request Body + +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": true +} +``` + +- `type`: Must be `true` for node attributes + +#### Responses + +- **200**: Attribute removed successfully + +### **Add/Update attribute to relationship** - `PATCH /api/schema/{schema}/{relationshipId}/{key}` + +Add a new attribute or update an existing attribute on a relationship in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name (example: `test`) +- `relationshipId` (path, required): Relationship ID (example: `1`) +- `key` (path, required): Attribute key to add/update (example: `since`) + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `type`, `attribute` + +Example request: +```json +{ + "type": false, + "attribute": ["STRING", "2024", "false", "false"] +} +``` + +- `type`: Must be `false` for relationship attributes +- `attribute`: Attribute configuration `[type, default, unique, required]` + +#### Responses + +- **200**: Attribute added/updated successfully + +### **Remove attribute from relationship** - `DELETE /api/schema/{schema}/{relationshipId}/{key}` + +Remove a specific attribute from a relationship in the schema. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `schema` (path, required): Schema name (example: `test`) +- `relationshipId` (path, required): Relationship ID (example: `1`) +- `key` (path, required): Attribute key to remove (example: `since`) + +#### Request Body + +- Content-Type: `application/json` +- Required field: `type` + +Example request: +```json +{ + "type": false +} +``` + +- `type`: Must be `false` for relationship attributes + +#### Responses + +- **200**: Attribute removed successfully + +--- + +## User Management + +### **List all users** - `GET /api/user` + +Get a list of all FalkorDB users. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Responses + +- **200**: List of users retrieved successfully - Content-Type: `application/json` - Example response: ```json { - "message": "SchemaName schema deleted" + "result": [ + { + "username": "john_doe", + "role": "Read-Write", + "selected": false + }, + { + "username": "admin_user", + "role": "Admin", + "selected": false + } + ] } ``` + +- **400**: Bad request +- **500**: Internal server error + +### **Create new user** - `POST /api/user` + +Create a new FalkorDB user with specified username, password, and role. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Request Body + +- Content-Type: `application/json` +- Required fields: `username`, `password`, `role` + +Example request: +```json +{ + "username": "new_user", + "password": "secure_password", + "role": "Read-Write" +} +``` + +- `username`: Username for the new user +- `password`: Password for the new user +- `role`: Role to assign to the user (`Admin`, `Read-Write`, `Read-Only`) + +#### Responses + +- **201**: User created successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Success" + } + ``` + + - Headers: + - `location`: Location of the created user resource (example: `/api/db/user/new_user`) + +- **400**: Bad request - missing parameters +- **409**: User already exists +- **500**: Internal server error + +### **Delete multiple users** - `DELETE /api/user` + +Delete multiple FalkorDB users by providing an array of usernames. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Request Body + +- Content-Type: `application/json` +- Required field: `users` + +Example request: +```json +{ + "users": [ + { "username": "user_1741261105156" }, + { "username": "another_user" } + ] +} +``` + +- `users`: Array of user objects to delete + +#### Responses + +- **200**: Users deleted successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Users deleted" + } + ``` + +- **400**: Bad request +- **500**: Internal server error + +### **Update user role** - `PATCH /api/user/{user}` + +Update the role of a FalkorDB user. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `user` (path, required): Username to update +- `role` (query, required): New role for the user (`Admin`, `Read-Write`, `Read-Only`) + +#### Responses + +- **200**: User role updated successfully + +--- + +## Error Responses + +All endpoints may return the following common error responses: + +- **401**: Unauthorized - Invalid or missing authentication token +- **403**: Forbidden - Insufficient permissions for the requested operation +- **404**: Not Found - Requested resource does not exist +- **500**: Internal Server Error - Unexpected server error + +## Data Types + +### Attribute Types +The following data types are supported for node and relationship attributes: + +- `STRING`: Text values +- `INTEGER`: Numeric integer values +- `FLOAT`: Numeric decimal values +- `BOOLEAN`: True/false values + +### Attribute Configuration +When defining attributes, use the following format: +```json +[type, default_value, unique, required] +``` + +- `type`: One of the supported data types (`STRING`, `INTEGER`, `FLOAT`, `BOOLEAN`) +- `default_value`: Default value for the attribute +- `unique`: `"true"` if the attribute must be unique, `"false"` otherwise +- `required`: `"true"` if the attribute is required, `"false"` otherwise + +Example: +```json +["STRING", "default_name", "false", "true"] +``` From 79fea7ce4cf0196cba72b4108ecf26a994a66598 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:13:30 +0300 Subject: [PATCH 002/107] add getting started --- integration/rest.md | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/integration/rest.md b/integration/rest.md index 8690ea58..b60dd2c8 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -15,6 +15,59 @@ REST API for FalkorDB Browser - Graph Database Management Interface **Authentication:** Bearer Token (JWT) +## Getting Started + +### Quick Start Guide + +To start using the FalkorDB Browser REST API, follow these simple steps: + +#### 1. Authentication +First, you need to authenticate to get a JWT token: + +```bash +curl -X POST "http://your-falkordb-browser-url/api/auth/login" \ + -H "Content-Type: application/json" \ + -d '{ + "username": "default", + "password": "password" + }' +``` + +This will return a JWT token that you'll use for all subsequent requests: +```json +{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "user": { + "username": "default", + "role": "Admin" + } +} +``` + +#### 2. Check Connection Status +Verify that FalkorDB is running and accessible: + +```bash +curl -X GET "http://your-falkordb-browser-url/api/status" \ + -H "Authorization: Bearer YOUR_JWT_TOKEN" +``` + +#### 3. List Available Graphs +See what graphs are available in your FalkorDB instance: + +```bash +curl -X GET "http://your-falkordb-browser-url/api/graph" \ + -H "Authorization: Bearer YOUR_JWT_TOKEN" +``` + +#### 4. Execute Your First Query +Run a simple Cypher query on a graph: + +```bash +curl -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH (n) RETURN n LIMIT 5&timeout=30000" \ + -H "Authorization: Bearer YOUR_JWT_TOKEN" +``` + ## Table of Contents ### Authentication From 92b4beea29c854813c9b3812b0727897542a917f Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:59:54 +0300 Subject: [PATCH 003/107] update rest api --- integration/rest.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/integration/rest.md b/integration/rest.md index b60dd2c8..e3958cbc 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -36,7 +36,7 @@ curl -X POST "http://your-falkordb-browser-url/api/auth/login" \ This will return a JWT token that you'll use for all subsequent requests: ```json { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "token": "", "user": { "username": "default", "role": "Admin" @@ -49,23 +49,26 @@ Verify that FalkorDB is running and accessible: ```bash curl -X GET "http://your-falkordb-browser-url/api/status" \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" + -H "Authorization: Bearer $JWT_TOKEN" ``` #### 3. List Available Graphs See what graphs are available in your FalkorDB instance: ```bash +AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}" curl -X GET "http://your-falkordb-browser-url/api/graph" \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" + -H "$AUTH_HEADER" ``` #### 4. Execute Your First Query Run a simple Cypher query on a graph: ```bash -curl -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH (n) RETURN n LIMIT 5&timeout=30000" \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" +AUTH_HEADER="Authorization: Bearer ${JWT_TOKEN}" +curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH%20(n)%20RETURN%20n%20LIMIT%205&timeout=30000" \ + -H "$AUTH_HEADER" \ + -H "Accept: text/event-stream" ``` ## Table of Contents @@ -107,14 +110,14 @@ curl -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH (n) - [Rename schema - PATCH /api/schema/{schema}](#rename-schema---patch-apischemaschema) - [Delete schema - DELETE /api/schema/{schema}](#delete-schema---delete-apischemaschema) - [Get schema element counts - GET /api/schema/{schema}/count](#get-schema-element-counts---get-apischemaschemacount) -- [Duplicate schema - PATCH /api/schema/{schema}/duplicate](#duplicate-schema---patch-apischemaschemaduplicat) +- [Duplicate schema - PATCH /api/schema/{schema}/duplicate](#duplicate-schema---patch-apischemaschemaduplicate) - [Create node or relationship in schema - POST /api/schema/{schema}/new](#create-node-or-relationship-in-schema---post-apischemaschemanew) -- [Create node in schema - POST /api/schema/{schema}/nodes](#create-node-in-schema---post-apischemaschemanode) +- [Create node in schema - POST /api/schema/{schema}/nodes](#create-node-in-schema---post-apischemaschemanodes) - [Create relationship in schema - POST /api/schema/{schema}/relationships](#create-relationship-in-schema---post-apischemaschemarelationships) - [Delete node from schema - DELETE /api/schema/{schema}/{nodeId}](#delete-node-from-schema---delete-apischemaschemanodeid) - [Delete relationship from schema - DELETE /api/schema/{schema}/{relationshipId}](#delete-relationship-from-schema---delete-apischemaschemarelationshipid) -- [Add label to node - POST /api/schema/{schema}/{node}/label](#add-label-to-node---post-apischemaschemanode/label) -- [Remove label from node - DELETE /api/schema/{schema}/{node}/label](#remove-label-from-node---delete-apischemaschemanode/label) +- [Add label to node - POST /api/schema/{schema}/{node}/label](#add-label-to-node---post-apischemaschemanodelabel) +- [Remove label from node - DELETE /api/schema/{schema}/{node}/label](#remove-label-from-node---delete-apischemaschemanodelabel) - [Add/Update attribute to node - PATCH /api/schema/{schema}/{nodeId}/{key}](#addupdate-attribute-to-node---patch-apischemaschemanodeidkey) - [Remove attribute from node - DELETE /api/schema/{schema}/{nodeId}/{key}](#remove-attribute-from-node---delete-apischemaschemanodeidkey) - [Add/Update attribute to relationship - PATCH /api/schema/{schema}/{relationshipId}/{key}](#addupdate-attribute-to-relationship---patch-apischemaschemarelationshipidkey) @@ -160,7 +163,7 @@ Example request: ```json { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "token": "", "user": { "username": "default", "role": "Admin" From f2ac198da85b4f67b3ded620d9d5913391d110f0 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:10:12 +0300 Subject: [PATCH 004/107] update wordlist --- .wordlist.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.wordlist.txt b/.wordlist.txt index 368ecf1a..d352514e 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -47,6 +47,7 @@ IndexError JS JSDoc JSON +JWT KJDev Kepner Keren @@ -186,6 +187,7 @@ myGraph myPassword myUsername namespace +nodeId nan nav nd @@ -227,6 +229,7 @@ redisgraph relDirection relTypes relationshipTypes +relationshipId reltype reltype reltypeList @@ -305,6 +308,7 @@ falkorDB GraphName api auth +backend callbackUrl csrf csrfToken From 2f390ee231190d17f5d12dca3186b52b29630b5b Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:23:03 +0200 Subject: [PATCH 005/107] Add JWT token management endpoints to REST API docs --- .wordlist.txt | 1 + integration/rest.md | 168 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index d352514e..e11b7a23 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -48,6 +48,7 @@ JS JSDoc JSON JWT +tokenId KJDev Kepner Keren diff --git a/integration/rest.md b/integration/rest.md index e3958cbc..543006f6 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -29,7 +29,7 @@ curl -X POST "http://your-falkordb-browser-url/api/auth/login" \ -H "Content-Type: application/json" \ -d '{ "username": "default", - "password": "password" + "password": "" }' ``` @@ -75,6 +75,9 @@ curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH% ### Authentication - [User login - POST /api/auth/login](#user-login---post-apiauthlogin) +- [Revoke JWT token - POST /api/auth/revoke](#revoke-jwt-token---post-apiauthrevoke) +- [List JWT tokens - GET /api/auth/tokens](#list-jwt-tokens---get-apiauthtokens) +- [Get token metadata - GET /api/auth/token/{tokenId}](#get-token-metadata---get-apiauthtokentokenid) ### Status - [Check FalkorDB connection status - GET /api/status](#check-falkordb-connection-status---get-apistatus) @@ -151,7 +154,7 @@ Example request: ```json { "username": "default", - "password": "password" + "password": "" } ``` @@ -175,6 +178,167 @@ Example request: - **401**: Invalid credentials - **500**: Internal server error +### **Revoke JWT token** - `POST /api/auth/revoke` + +Revoke a JWT token by removing it from the active tokens list in Redis. Once revoked, the token cannot be used for authentication. Admins can revoke any token, while regular users can only revoke their own tokens. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Request Body + +- Content-Type: `application/json` +- Required field: `token` + +Example request: +```json +{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +#### Responses + +- **200**: Token revoked successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token revoked successfully", + "tokenId": "user-123-1640995200" + } + ``` + +- **400**: Bad request - missing token in request body + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token to revoke is required in request body" + } + ``` + +- **401**: Authentication failed - invalid or missing token + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Authorization header with Bearer token required" + } + ``` + +- **403**: Forbidden - You can only revoke your own tokens (unless you are an Admin) + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Forbidden: You can only revoke your own tokens" + } + ``` + +- **500**: Server configuration error + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Server configuration error" + } + ``` + +### **List JWT tokens** - `GET /api/auth/tokens` + +Get a list of active JWT tokens. Admins can see all tokens from all users, while regular users can only see their own tokens. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Responses + +- **200**: List of tokens retrieved successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "tokens": [ + { + "user_id": "7262bcaecc2b06ff66e28ede90e6dce39c218685af9272d7a3fbd63ae08d17c2", + "token_id": "1761055513181-215c579b-c6e1-4f10-9b07-aacbf89cda21", + "created_at": "2025-10-21T14:05:13.182Z", + "expires_at": "2026-10-21T14:05:13.182Z", + "last_used": null, + "name": "API Token", + "permissions": ["Admin"], + "username": "adminuser" + } + ], + "count": 8 + } + ``` + +- **401**: Authentication failed - invalid or missing token +- **500**: Internal server error + +### **Get token metadata** - `GET /api/auth/token/{tokenId}` + +Get detailed metadata for a specific JWT token by its token ID. Admins can view any token, while regular users can only view their own tokens. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `tokenId` (path, required): Token ID to retrieve + - Example: `1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81` + +#### Responses + +- **200**: Token metadata retrieved successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "token": { + "user_id": "e5d09e7d2141f77f80008ff73f04104b9484f59baa8e19a4ea758495d289fd0f", + "token_id": "1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81", + "created_at": "2025-10-21T13:25:08.085Z", + "expires_at": "2026-10-21T13:25:08.085Z", + "last_used": null, + "name": "API Token", + "permissions": ["Read-Only"], + "username": "readonlyuser" + } + } + ``` + +- **401**: Authentication failed - invalid or missing token +- **403**: Forbidden - You can only view your own tokens (unless you are an Admin) + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Forbidden: You can only view your own tokens" + } + ``` + +- **404**: Token not found + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token not found" + } + ``` + +- **500**: Internal server error + --- ## Status From 6366c62f93421387f07dfb08bbcc12ae922a382f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 01:03:06 +0200 Subject: [PATCH 006/107] Add logo_link configuration support to link logo to www.falkordb.com (#252) * Add logo_link configuration to point to www.falkordb.com --- _config.yml | 1 + _includes/components/sidebar.html | 36 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 _includes/components/sidebar.html diff --git a/_config.yml b/_config.yml index a014c6ea..efccb889 100644 --- a/_config.yml +++ b/_config.yml @@ -2,6 +2,7 @@ remote_theme: just-the-docs/just-the-docs title: FalkorDB Docs description: The FalkorDB documentation logo: "/images/falkor-logo.png" +logo_link: "https://www.falkordb.com" favicon_ico: "/images/favicon.ico" gtm_tracking: GTM-MBWB627H diff --git a/_includes/components/sidebar.html b/_includes/components/sidebar.html new file mode 100644 index 00000000..49c305f8 --- /dev/null +++ b/_includes/components/sidebar.html @@ -0,0 +1,36 @@ +{%- comment -%} + Include as: {%- include components/sidebar.html -%} + Depends on: page(?), site. + Results in: HTML for the side bar. + Includes: + title.html, components/site_nav.html, nav_footer_custom.html + Overwrites: + nav_footer_custom. + Should not be cached, because nav_footer_custom.html might depend on page. +{%- endcomment -%} + + From 312904e1dc005536a858f4642c44b4b981b86937 Mon Sep 17 00:00:00 2001 From: Shahar Biron <38566538+shahar-biron@users.noreply.github.com> Date: Sun, 9 Nov 2025 15:09:40 +0200 Subject: [PATCH 007/107] docs: add db.meta.stats() procedure documentation --- cypher/procedures.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cypher/procedures.md b/cypher/procedures.md index ebd4e80a..0e7c11f6 100644 --- a/cypher/procedures.md +++ b/cypher/procedures.md @@ -27,6 +27,7 @@ YIELD modifiers are only required if explicitly specified; by default the value | db.labels | none | `label` | Yields all node labels in the graph. | | db.relationshipTypes | none | `relationshipType` | Yields all relationship types in the graph. | | db.propertyKeys | none | `propertyKey` | Yields all property keys in the graph. | +| db.meta.stats | none | `labels`, `relTypes`, `relCount`, `nodeCount`, `labelCount`, `relTypeCount`, `propertyKeyCount` | Returns comprehensive graph statistics including maps of labels and relationship types with their counts, total node/relationship counts, and schema metadata counts. | | db.indexes | none | `label`, `properties`, `types`, `options`, `language`, `stopwords`, `entitytype`, `status`, `info` | Yield all indexes in the graph, denoting whether they are of the type of exact-match ("RANGE"), full-text ("FULLTEXT") or vector ("VECTOR") and which label and properties each covers and whether they are indexing node or relationship attributes. | | db.constraints | none | `type`, `label`, `properties`, `entitytype`, `status` | Yield all constraints in the graph, denoting constraint type (UNIQIE/MANDATORY), which label/relationship-type and properties each enforces. | | db.idx.fulltext.createNodeIndex | `label`, `property` [, `property` ...] | none | Builds a full-text searchable index on a label and the 1 or more specified properties. | From 2c70727ccc159dac3ac980a4a6e80a108f9da270 Mon Sep 17 00:00:00 2001 From: Shahar Biron <38566538+shahar-biron@users.noreply.github.com> Date: Sun, 9 Nov 2025 15:27:56 +0200 Subject: [PATCH 008/107] Update db.meta.stats description for clarity use Yield term as in other procedures --- cypher/procedures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypher/procedures.md b/cypher/procedures.md index 0e7c11f6..d8305e0e 100644 --- a/cypher/procedures.md +++ b/cypher/procedures.md @@ -27,7 +27,7 @@ YIELD modifiers are only required if explicitly specified; by default the value | db.labels | none | `label` | Yields all node labels in the graph. | | db.relationshipTypes | none | `relationshipType` | Yields all relationship types in the graph. | | db.propertyKeys | none | `propertyKey` | Yields all property keys in the graph. | -| db.meta.stats | none | `labels`, `relTypes`, `relCount`, `nodeCount`, `labelCount`, `relTypeCount`, `propertyKeyCount` | Returns comprehensive graph statistics including maps of labels and relationship types with their counts, total node/relationship counts, and schema metadata counts. | +| db.meta.stats | none | `labels`, `relTypes`, `relCount`, `nodeCount`, `labelCount`, `relTypeCount`, `propertyKeyCount` | Yield comprehensive graph statistics including maps of labels and relationship types with their counts, total node/relationship counts, and schema metadata counts. | | db.indexes | none | `label`, `properties`, `types`, `options`, `language`, `stopwords`, `entitytype`, `status`, `info` | Yield all indexes in the graph, denoting whether they are of the type of exact-match ("RANGE"), full-text ("FULLTEXT") or vector ("VECTOR") and which label and properties each covers and whether they are indexing node or relationship attributes. | | db.constraints | none | `type`, `label`, `properties`, `entitytype`, `status` | Yield all constraints in the graph, denoting constraint type (UNIQIE/MANDATORY), which label/relationship-type and properties each enforces. | | db.idx.fulltext.createNodeIndex | `label`, `property` [, `property` ...] | none | Builds a full-text searchable index on a label and the 1 or more specified properties. | From 23c0d586c5dab512e30567ca1ed5932432ea7849 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Mon, 10 Nov 2025 10:38:20 +0200 Subject: [PATCH 009/107] fix redirect (#274) * fix redirect --- algorithms/index.md | 3 +++ genai-tools/index.md | 2 ++ integration/bolt-support.md | 2 ++ operations/replication.md | 5 ++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/algorithms/index.md b/algorithms/index.md index a23e57f7..14188c37 100644 --- a/algorithms/index.md +++ b/algorithms/index.md @@ -3,6 +3,9 @@ title: "Algorithms" description: Graph Algorithms Overview nav_order: 3 has_children: true +redirect_from: + - /cypher/algorithms.html + - /cypher/algorithms --- # FalkorDB Algorithms Overview diff --git a/genai-tools/index.md b/genai-tools/index.md index e5363247..86220065 100644 --- a/genai-tools/index.md +++ b/genai-tools/index.md @@ -8,6 +8,8 @@ redirect_from: - /llm_integrations - /llm-integrations.html - /llm-integrations + - /llm_support.html + - /llm_support --- # GenAI Tools diff --git a/integration/bolt-support.md b/integration/bolt-support.md index 948b4f5c..5eafdc3a 100644 --- a/integration/bolt-support.md +++ b/integration/bolt-support.md @@ -6,6 +6,8 @@ parent: "Integration" redirect_from: - /bolt-support.html - /bolt-support + - /bolt_support.html + - /bolt_support --- # [EXPERIMENTAL] BOLT protocol support for FalkorDB diff --git a/operations/replication.md b/operations/replication.md index a2e8001e..47bdeef6 100644 --- a/operations/replication.md +++ b/operations/replication.md @@ -3,6 +3,9 @@ title: "Replication" nav_order: 2 description: "Configuring FalkorDB Docker for Replication" parent: "Operations" +redirect_from: + - /operation/replication + - /operation/replication.html --- # Configuring FalkorDB Docker for Replication @@ -100,4 +103,4 @@ redis-cli graph.ro_query mygraph "MATCH (n) return n" With replication configured, FalkorDB is now set up for high availability and data redundancy, ensuring that your data is synchronized across multiple instances. This setup provides a robust and fault-tolerant environment for your applications. -If you're interested in learning more about clustering and scaling out, be sure to check out the [Cluster](/operations/cluster) chapter in the documentation. \ No newline at end of file +If you're interested in learning more about clustering and scaling out, be sure to check out the [Cluster](/operations/cluster) chapter in the documentation. From 80474adaeb1d3530a18bdb6dc065919cea848951 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Mon, 10 Nov 2025 10:42:05 +0200 Subject: [PATCH 010/107] Update index.md (#275) --- operations/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/operations/index.md b/operations/index.md index 16b89a47..118812ab 100644 --- a/operations/index.md +++ b/operations/index.md @@ -2,6 +2,9 @@ title: "Operations" nav_order: 10 description: "Configuring FalkorDB Docker" +redirect_from: + - /operation + - /operation.html --- # Operations From 72cd374b1cdd455103e1d88f180f07248e2d991c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 00:55:48 +0200 Subject: [PATCH 011/107] Update Graphiti MCP docs to align with official Zep implementation (#276) * Update Graphiti MCP docs to use official Zep configuration --- .wordlist.txt | 7 + agentic-memory/graphiti-mcp-server.md | 365 ++++++++++++++++---------- 2 files changed, 228 insertions(+), 144 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 9bf266f7..b74c2988 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -25,6 +25,7 @@ DateTime DELUSER distro Ducati +Embedder FOF FOREACH Falkor @@ -35,6 +36,7 @@ FalkorDBGraph FalkorDBLite FalkorDBQAChain Gadepally +Gemini Geospatial GETUSER GPL @@ -117,6 +119,7 @@ Subcommands TF TTY TypeScript +UI UNIQIE URIs UUID @@ -175,6 +178,7 @@ falkordblite fulltext geospatial godoc +gpt hasLabels haversin html @@ -309,6 +313,7 @@ weightProp whitespace xyxel yaml +yml uri util vec @@ -431,6 +436,8 @@ cognee cognify topoteretes getzep +zepai +Zep's prune qdrant TechCorp diff --git a/agentic-memory/graphiti-mcp-server.md b/agentic-memory/graphiti-mcp-server.md index 8f60d049..804a78c3 100644 --- a/agentic-memory/graphiti-mcp-server.md +++ b/agentic-memory/graphiti-mcp-server.md @@ -5,86 +5,113 @@ nav_order: 3 description: "Run Graphiti MCP server with FalkorDB for AI agent memory in Claude Desktop and other MCP clients" --- -# [EXPERIMENTAL] Graphiti MCP Server +# Graphiti MCP Server -{: .warning } -> **Experimental Feature**: The Graphiti MCP Server integration is experimental and under active development. Features and configurations may change in future releases. - -The Graphiti MCP (Model Context Protocol) Server enables AI clients like Claude Desktop and Cursor IDE to interact with FalkorDB-powered knowledge graphs for persistent agent memory. This allows AI assistants to store and retrieve information across conversations, building a rich, contextual memory over time. +Graphiti is a framework for building and querying temporally-aware knowledge graphs, specifically tailored for AI agents operating in dynamic environments. The Graphiti MCP (Model Context Protocol) Server enables AI clients like Claude Desktop, Cursor IDE, and other MCP-compatible applications to interact with FalkorDB-powered knowledge graphs for persistent agent memory. This allows AI assistants to store and retrieve information across conversations, building a rich, contextual memory over time. ## What is MCP? The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard that enables AI applications to connect to external data sources and tools. The Graphiti MCP Server implements this protocol to provide AI agents with access to graph-based knowledge storage powered by FalkorDB. -## Overview +## Features + +The Graphiti MCP Server provides comprehensive knowledge graph capabilities: -The Graphiti MCP Server provides: -- **Persistent Memory**: Store conversation history, facts, and relationships in a knowledge graph -- **Contextual Retrieval**: Query the graph to retrieve relevant information for AI responses -- **Cross-Session Memory**: Maintain knowledge across multiple conversations and sessions -- **Multi-Tenant Support**: Isolated memory spaces for different users or agents -- **Real-Time Updates**: Add new information to the graph as conversations evolve +- **Episode Management**: Add, retrieve, and delete episodes (text, messages, or JSON data) +- **Entity Management**: Search and manage entity nodes and relationships in the knowledge graph +- **Search Capabilities**: Search for facts (edges) and node summaries using semantic and hybrid search +- **Group Management**: Organize and manage groups of related data with group_id filtering +- **Graph Maintenance**: Clear the graph and rebuild indices +- **Multiple LLM Providers**: Support for OpenAI, Anthropic, Gemini, Groq, and Azure OpenAI +- **Multiple Embedding Providers**: Support for OpenAI, Voyage, Sentence Transformers, and Gemini embeddings +- **Rich Entity Types**: Built-in entity types including Preferences, Requirements, Procedures, Locations, Events, Organizations, Documents, and more for structured knowledge extraction +- **HTTP Transport**: Default HTTP transport with MCP endpoint at `/mcp/` for broad client compatibility +- **Queue-based Processing**: Asynchronous episode processing with configurable concurrency limits ## Prerequisites Before you begin, ensure you have: -- Docker installed on your system -- An OpenAI API key (for LLM operations) -- A FalkorDB instance running (or use the bundled Docker setup) +- Docker and Docker Compose installed on your system +- At least one LLM provider API key: + - OpenAI API key (recommended) + - Or Anthropic, Gemini, Groq, or Azure OpenAI API key +- (Optional) Python 3.10+ if running the MCP server standalone with an external FalkorDB instance -## Quick Start with Docker +## Quick Start with Docker Compose -The easiest way to run the Graphiti MCP Server with FalkorDB is using Docker: +The easiest way to run the Graphiti MCP Server with FalkorDB is using the official Docker Compose configuration from [Zep's Graphiti repository](https://github.com/getzep/graphiti/tree/main/mcp_server). -### Step 1: Pull the Docker Image +### Option 1: Combined Image (Recommended) + +This setup uses a single container that includes both FalkorDB and the MCP server. + +1. **Create a directory for your setup:** ```bash -docker pull falkordb/graphiti-knowledge-graph-mcp:latest +mkdir graphiti-mcp && cd graphiti-mcp ``` -### Step 2: Run the MCP Server +2. **Download the docker-compose configuration:** -Run the server with required environment variables: +```bash +curl -O https://raw.githubusercontent.com/getzep/graphiti/main/mcp_server/docker/docker-compose.yml +``` + +3. **Create a `.env` file with your API key:** + +```env +OPENAI_API_KEY=your-openai-api-key +FALKORDB_PASSWORD= +GRAPHITI_GROUP_ID=main +``` + +4. **Start the services:** ```bash -docker run -d \ - --name graphiti-mcp \ - -e OPENAI_API_KEY="your-openai-api-key" \ - -e DATABASE_TYPE="falkordb" \ - -e FALKORDB_HOST="host.docker.internal" \ - -e FALKORDB_PORT="6379" \ - -p 8000:8000 \ - falkordb/graphiti-knowledge-graph-mcp:latest +docker-compose up -d ``` -**Note**: If you're running FalkorDB on your local machine, use `host.docker.internal` as the `FALKORDB_HOST` to allow the container to access your host's localhost. +The combined image will start both FalkorDB and the MCP server in a single container, accessible at: +- **FalkorDB (Redis):** `localhost:6379` +- **FalkorDB Browser UI:** `http://localhost:3000` +- **MCP Server HTTP endpoint:** `http://localhost:8000/mcp/` +- **Health check:** `http://localhost:8000/health` + +### Option 2: Separate Containers -#### Alternative: Using a .env File +For more flexibility, you can run FalkorDB and the MCP server in separate containers. -For easier management of environment variables, create a `.env` file: +1. **Create a directory and download the configuration:** + +```bash +mkdir graphiti-mcp && cd graphiti-mcp +curl -O https://raw.githubusercontent.com/getzep/graphiti/main/mcp_server/docker/docker-compose-falkordb.yml +mv docker-compose-falkordb.yml docker-compose.yml +``` + +2. **Create a `.env` file:** ```env OPENAI_API_KEY=your-openai-api-key -DATABASE_TYPE=falkordb -FALKORDB_HOST=host.docker.internal -FALKORDB_PORT=6379 -FALKORDB_USERNAME= +FALKORDB_URI=redis://falkordb:6379 FALKORDB_PASSWORD= +FALKORDB_DATABASE=default_db +GRAPHITI_GROUP_ID=main ``` -Then run the container with the `--env-file` option: +3. **Start the services:** ```bash -docker run -d \ - --name graphiti-mcp \ - --env-file .env \ - -p 8000:8000 \ - falkordb/graphiti-knowledge-graph-mcp:latest +docker-compose up -d ``` -### Step 3: Run FalkorDB (if needed) +This configuration starts FalkorDB and the MCP server as separate containers with the same accessible ports as the combined image. + +## Manual Docker Setup (Alternative) -If you don't have a FalkorDB instance running, start one: +If you prefer to run containers manually without Docker Compose, you can use the standalone MCP server image: + +### Step 1: Run FalkorDB ```bash docker run -d \ @@ -94,89 +121,106 @@ docker run -d \ falkordb/falkordb:latest ``` -## Docker Compose Setup - -For a complete setup with both FalkorDB and the MCP server, create a `docker-compose.yml`: - -```yaml -version: '3.8' - -services: - falkordb: - image: falkordb/falkordb:latest - ports: - - "6379:6379" # Redis protocol port - - "3000:3000" # FalkorDB Browser UI - volumes: - - falkordb-data:/data - - graphiti-mcp: - image: falkordb/graphiti-knowledge-graph-mcp:latest - depends_on: - - falkordb - ports: - - "8000:8000" # MCP Server HTTP/SSE port - environment: - - OPENAI_API_KEY=${OPENAI_API_KEY} - - DATABASE_TYPE=falkordb - - FALKORDB_HOST=falkordb - - FALKORDB_PORT=6379 - - FALKORDB_USERNAME=${FALKORDB_USERNAME:-} - - FALKORDB_PASSWORD=${FALKORDB_PASSWORD:-} - -volumes: - falkordb-data: +### Step 2: Run the MCP Server + +```bash +docker run -d \ + --name graphiti-mcp \ + -e OPENAI_API_KEY="your-openai-api-key" \ + -e FALKORDB_URI="redis://host.docker.internal:6379" \ + -e FALKORDB_PASSWORD="" \ + -e FALKORDB_DATABASE="default_db" \ + -e GRAPHITI_GROUP_ID="main" \ + -p 8000:8000 \ + zepai/knowledge-graph-mcp:standalone ``` -Create a `.env` file in the same directory: +**Note**: Use `host.docker.internal` as the hostname to allow the container to access FalkorDB running on your host machine. + +## Configuration + +The Graphiti MCP server can be configured using environment variables in a `.env` file or through a `config.yaml` file. + +### Default Configuration +The MCP server comes with sensible defaults: +- **Transport**: HTTP (accessible at `http://localhost:8000/mcp/`) +- **Database**: FalkorDB (combined in single container with MCP server) +- **LLM**: OpenAI with model gpt-4o-mini +- **Embedder**: OpenAI text-embedding-3-small + +### LLM Provider Configuration + +The server supports multiple LLM providers. Set the appropriate API key in your `.env` file: + +**OpenAI (default)**: ```env -OPENAI_API_KEY=your-openai-api-key -DATABASE_TYPE=falkordb -FALKORDB_USERNAME= -FALKORDB_PASSWORD= +OPENAI_API_KEY=sk-proj-your-key-here ``` -Then start both services: +**Anthropic**: +```env +ANTHROPIC_API_KEY=your-anthropic-key +``` -```bash -docker-compose up -d +**Google Gemini**: +```env +GOOGLE_API_KEY=your-google-key ``` -## Configuration +**Groq**: +```env +GROQ_API_KEY=your-groq-key +``` + +**Azure OpenAI**: +```env +AZURE_OPENAI_API_KEY=your-azure-key +AZURE_OPENAI_ENDPOINT=your-endpoint-url +AZURE_OPENAI_DEPLOYMENT=your-deployment-name +``` ### Environment Variables -The MCP server accepts the following environment variables: +Key environment variables for the MCP server: | Variable | Description | Default | Required | Example | |----------|-------------|---------|----------|---------| -| `OPENAI_API_KEY` | Your OpenAI API key for LLM operations | - | Yes | `sk-proj-...` | -| `DATABASE_TYPE` | Database backend type (must be "falkordb") | - | Yes | `falkordb` | -| `FALKORDB_HOST` | FalkorDB server hostname | `localhost` | No | `host.docker.internal` | -| `FALKORDB_PORT` | FalkorDB server port | `6379` | No | `6379` | -| `FALKORDB_USERNAME` | FalkorDB username (if authentication enabled) | - | No | `default` | +| `OPENAI_API_KEY` | OpenAI API key (or use another LLM provider) | - | Yes* | `sk-proj-...` | +| `FALKORDB_URI` | FalkorDB connection URI | `redis://localhost:6379` | No | `redis://falkordb:6379` | | `FALKORDB_PASSWORD` | FalkorDB password (if authentication enabled) | - | No | `your-password` | -| `PORT` | MCP server port | `8000` | No | `8000` | -| `MODEL_NAME` | OpenAI model to use | `gpt-4o-mini` | No | `gpt-5` | +| `FALKORDB_DATABASE` | Database name | `default_db` | No | `default_db` | +| `SEMAPHORE_LIMIT` | Episode processing concurrency limit | `10` | No | `10` | +| `BROWSER` | Enable FalkorDB Browser UI (combined image) | `1` | No | `1` | + +*At least one LLM provider API key is required + +### Concurrency and Rate Limits + +The `SEMAPHORE_LIMIT` controls how many episodes can be processed simultaneously. Adjust based on your LLM provider tier: + +- **OpenAI Tier 1 (free)**: `SEMAPHORE_LIMIT=1-2` +- **OpenAI Tier 2**: `SEMAPHORE_LIMIT=5-8` +- **OpenAI Tier 3**: `SEMAPHORE_LIMIT=10-15` +- **OpenAI Tier 4**: `SEMAPHORE_LIMIT=20-50` +- **Anthropic default**: `SEMAPHORE_LIMIT=5-8` + +If you see 429 rate limit errors, reduce the value. Monitor your LLM provider's dashboard for actual request rates. ### FalkorDB Cloud Configuration -To use FalkorDB Cloud with the MCP server: +To use FalkorDB Cloud with the MCP server, update your `.env` file: -```bash -docker run -d \ - --name graphiti-mcp \ - -e OPENAI_API_KEY="your-openai-api-key" \ - -e DATABASE_TYPE="falkordb" \ - -e FALKORDB_HOST="your-instance.falkordb.cloud" \ - -e FALKORDB_PORT="6379" \ - -e FALKORDB_USERNAME="default" \ - -e FALKORDB_PASSWORD="your-cloud-password" \ - -p 8000:8000 \ - falkordb/graphiti-knowledge-graph-mcp:latest +```env +OPENAI_API_KEY=your-openai-api-key +FALKORDB_URI=redis://your-instance.falkordb.cloud:6379 +FALKORDB_PASSWORD=your-cloud-password +FALKORDB_DATABASE=default_db +GRAPHITI_GROUP_ID=main ``` +Then use the docker-compose configuration with the separate containers option (docker-compose-falkordb.yml), as it's designed for external database connections. + ## Client Integration ### Claude Desktop @@ -193,35 +237,37 @@ Add the following configuration: { "mcpServers": { "graphiti-memory": { - "transport": "sse", - "url": "http://localhost:8000/sse" + "transport": "http", + "url": "http://localhost:8000/mcp/" } } } ``` -**Note**: The MCP server uses Server-Sent Events (SSE) for real-time communication between the AI client and the knowledge graph. The `OPENAI_API_KEY` is already configured in the MCP server's Docker environment, so you don't need to specify it again here. +**Note**: The MCP server uses HTTP transport by default with the endpoint at `/mcp/`. The `OPENAI_API_KEY` is already configured in the MCP server's Docker environment, so you don't need to specify it again here. + +**Alternative (stdio transport)**: If you have the Graphiti repository cloned locally and Python installed, you can use stdio transport for better integration with some clients. See the [official Graphiti documentation](https://github.com/getzep/graphiti/blob/main/mcp_server/README.md#integrating-with-mcp-clients) for stdio configuration details. **After configuration**: 1. Restart Claude Desktop to apply the changes 2. Look for the MCP server indicator in Claude's interface 3. Claude will now have access to persistent memory through the knowledge graph -### Cursor IDE +### Cursor IDE and VS Code -For Cursor IDE, add the MCP server configuration to your Cursor settings: +For Cursor IDE and VS Code with GitHub Copilot, add the MCP server configuration: -1. Open Cursor IDE settings -2. Navigate to the MCP configuration section -3. Add the server configuration: +**Cursor IDE**: Add to Cursor settings + +**VS Code**: Add to `.vscode/mcp.json` or global settings ```json { - "mcp": { - "servers": { - "graphiti-memory": { - "url": "http://localhost:8000", - "transport": "sse" + "mcpServers": { + "graphiti-memory": { + "uri": "http://localhost:8000/mcp/", + "transport": { + "type": "http" } } } @@ -263,25 +309,36 @@ Once configured, test the connection with these steps: The AI will use the Graphiti MCP server to store and retrieve this information from the FalkorDB knowledge graph. -## MCP Server Capabilities +## Available Tools + +The Graphiti MCP server exposes the following tools to AI clients: + +- **`add_episode`**: Add an episode to the knowledge graph (supports text, JSON, and message formats) +- **`search_nodes`**: Search the knowledge graph for relevant node summaries +- **`search_facts`**: Search the knowledge graph for relevant facts (edges between entities) +- **`delete_entity_edge`**: Delete an entity edge from the knowledge graph +- **`delete_episode`**: Delete an episode from the knowledge graph +- **`get_entity_edge`**: Get an entity edge by its UUID +- **`get_episodes`**: Get the most recent episodes for a specific group +- **`clear_graph`**: Clear all data from the knowledge graph and rebuild indices -The Graphiti MCP server exposes the following capabilities to AI clients: +### Entity Types -### Tools +Graphiti MCP Server includes built-in entity types for structured knowledge extraction. The MCP server automatically uses these entity types during episode ingestion to extract and structure information from conversations and documents. -- **`add_episode`**: Store new information as an episode in the knowledge graph - - Extracts entities and relationships - - Adds temporal context - - Links to existing knowledge +**Available Entity Types:** -- **`search`**: Query the knowledge graph for relevant information - - Semantic search using embeddings - - Graph traversal for connected information - - Temporal filtering +- **Preference**: User preferences, choices, opinions, or selections (prioritized for user-specific information) +- **Requirement**: Specific needs, features, or functionality that must be fulfilled +- **Procedure**: Standard operating procedures and sequential instructions +- **Location**: Physical or virtual places where activities occur +- **Event**: Time-bound activities, occurrences, or experiences +- **Organization**: Companies, institutions, groups, or formal entities +- **Document**: Information content in various forms (books, articles, reports, videos, etc.) +- **Topic**: Subject of conversation, interest, or knowledge domain (used as a fallback) +- **Object**: Physical items, tools, devices, or possessions (used as a fallback) -- **`get_context`**: Retrieve contextual information for a conversation - - Builds relevant context from the graph - - Returns connected entities and relationships +These entity types can be customized in the `config.yaml` file if you're running the MCP server from source. ### Graph Schema @@ -305,16 +362,17 @@ The Graphiti MCP server stores information in FalkorDB using the following schem ### Programmatic Access {: .warning } -> **Important**: The Graphiti MCP server is designed to be used by MCP clients (like Claude Desktop or Cursor) via the Server-Sent Events (SSE) transport protocol. It does **not** expose HTTP REST API endpoints for direct programmatic access. +> **Important**: The Graphiti MCP server is designed to be used by MCP clients (like Claude Desktop or Cursor) via the HTTP transport protocol. It does **not** expose direct REST API endpoints outside of the MCP protocol. -The server only exposes: -- `/sse` - Server-Sent Events endpoint for MCP protocol communication +The server exposes: +- `/mcp/` - HTTP MCP protocol endpoint +- `/health` - Health check endpoint To interact with the Graphiti knowledge graph programmatically, you have two options: **Option 1: Use an MCP Client Library** -Use an MCP client library that implements the MCP protocol to communicate with the server via SSE. This is the intended way to interact with the server programmatically. +Use an MCP client library that implements the MCP protocol to communicate with the server via HTTP. This is the intended way to interact with the server programmatically. **Option 2: Access FalkorDB Directly** @@ -373,16 +431,32 @@ for record in result.result_set: ### View Server Logs -To view the MCP server logs: +To view the logs: + +**For combined image:** +```bash +docker logs -f graphiti-falkordb +``` +**For separate containers:** ```bash +# MCP server logs docker logs -f graphiti-mcp + +# FalkorDB logs +docker logs -f falkordb ``` ### Check FalkorDB Connection Verify the connection to FalkorDB using the Redis CLI: +**For combined image:** +```bash +docker exec -it graphiti-falkordb redis-cli PING +``` + +**For separate containers:** ```bash # Test from the FalkorDB container docker exec -it falkordb redis-cli PING @@ -391,7 +465,7 @@ docker exec -it falkordb redis-cli PING docker exec -it graphiti-mcp redis-cli -h falkordb -p 6379 PING ``` -Both commands should return `PONG` if the connection is successful. +All commands should return `PONG` if the connection is successful. ### Inspect the Knowledge Graph @@ -414,10 +488,11 @@ MATCH (n) RETURN n LIMIT 25 **Solutions**: - Verify FalkorDB is running: `docker ps | grep falkordb` - Test FalkorDB connection: `docker exec -it redis-cli PING` (should return `PONG`) -- Check network connectivity: Use `host.docker.internal` for local FalkorDB when running MCP server in Docker +- Check the `FALKORDB_URI` format: `redis://hostname:port` +- For separate containers, use the service name: `redis://falkordb:6379` +- For external FalkorDB, use `redis://host.docker.internal:6379` - Verify port 6379 is accessible - Check firewall settings -- Verify `DATABASE_TYPE=falkordb` environment variable is set (server won't start without it) ### Authentication Errors @@ -443,9 +518,10 @@ MATCH (n) RETURN n LIMIT 25 **Problem**: Claude Desktop or Cursor cannot connect to MCP server **Solutions**: -- Verify the MCP server is running: `docker ps | grep graphiti-mcp` -- Check the server logs: `docker logs graphiti-mcp` -- Test the SSE endpoint: `curl http://localhost:8000/sse` +- Verify the MCP server is running: `docker ps | grep graphiti` +- Check the server logs: `docker logs graphiti-mcp` (or `docker logs graphiti-falkordb` for combined image) +- Test the MCP endpoint: `curl http://localhost:8000/mcp/` +- Check the health endpoint: `curl http://localhost:8000/health` - Ensure the configuration file path is correct for your OS - Restart the client application after changing configuration - Check for port conflicts on port 8000: `lsof -i :8000` (macOS/Linux) or `netstat -ano | findstr :8000` (Windows) @@ -484,7 +560,8 @@ MATCH (n) RETURN n LIMIT 25 ## Resources -- 🐳 [Docker Hub Repository](https://hub.docker.com/r/falkordb/graphiti-knowledge-graph-mcp) +- 🐳 [Graphiti MCP Server Docker Setup](https://github.com/getzep/graphiti/tree/main/mcp_server/docker) +- 📦 [Docker Hub Repository](https://hub.docker.com/r/zepai/knowledge-graph-mcp) - 📚 [Model Context Protocol Documentation](https://modelcontextprotocol.io/) - 📖 [Graphiti Documentation](https://help.getzep.com/graphiti/) - 💻 [Graphiti GitHub Repository](https://github.com/getzep/graphiti) From 35780ba27068eb6f6d1004026afc26a621c7de72 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:01:28 +0200 Subject: [PATCH 012/107] Add Docker and Docker Compose operations documentation (#279) * Add comprehensive Docker and Docker Compose documentation --- operations/docker.md | 488 +++++++++++++++++++++++++++++++++++++++++++ operations/index.md | 24 ++- 2 files changed, 502 insertions(+), 10 deletions(-) create mode 100644 operations/docker.md diff --git a/operations/docker.md b/operations/docker.md new file mode 100644 index 00000000..c1c8cdf9 --- /dev/null +++ b/operations/docker.md @@ -0,0 +1,488 @@ +--- +title: "Docker and Docker Compose" +nav_order: 11 +parent: Operations +description: "Running FalkorDB with Docker and Docker Compose" +--- + +# Running FalkorDB with Docker and Docker Compose + +This guide covers how to run FalkorDB using Docker and Docker Compose, providing flexible deployment options for both development and production environments. + +## Docker Images + +FalkorDB provides two main Docker images: + +### 1. `falkordb/falkordb` +- **Includes**: FalkorDB server + FalkorDB Browser +- **Use case**: Development, quick start, interactive exploration +- **Ports**: + - `6379` - Redis/FalkorDB server + - `3000` - FalkorDB Browser UI + +### 2. `falkordb/falkordb-server` +- **Includes**: FalkorDB server only +- **Use case**: Production deployments, lighter footprint +- **Ports**: + - `6379` - Redis/FalkorDB server + +### 3. `falkordb/falkordb-browser` +- **Includes**: FalkorDB Browser UI only +- **Use case**: Running browser separately from the server, custom deployments +- **Ports**: + - `3000` - FalkorDB Browser UI +- **Configuration**: Requires `FALKORDB_URL` environment variable to connect to a FalkorDB server + +## Quick Start with Docker + +### Running with Browser (Development) + +```bash +docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest +``` + +Access the browser at [http://localhost:3000](http://localhost:3000) + +### Running Server Only (Production) + +```bash +docker run -p 6379:6379 -it --rm falkordb/falkordb-server:latest +``` + +### Running with Authentication + +```bash +docker run -p 6379:6379 -p 3000:3000 -it \ + -e REDIS_ARGS="--requirepass yourpassword" \ + --rm falkordb/falkordb:latest +``` + +### Running with Custom Configuration + +```bash +docker run -p 6379:6379 -p 3000:3000 -it \ + -e REDIS_ARGS="--requirepass yourpassword" \ + -e FALKORDB_ARGS="THREAD_COUNT 4 TIMEOUT 5000" \ + --rm falkordb/falkordb:latest +``` + +## Using Docker Compose + +Docker Compose provides a more flexible and maintainable way to run FalkorDB, especially when you need to configure multiple services or manage complex setups. + +> **Quick Start**: You can download a ready-to-use docker-compose.yml file from the [FalkorDB repository](https://github.com/FalkorDB/FalkorDB/blob/master/build/docker/docker-compose.yml). + +### Basic Docker Compose Setup + +Create a `docker-compose.yml` file: + +```yaml +version: '3.8' + +services: + falkordb: + image: falkordb/falkordb:latest + container_name: falkordb + ports: + - "6379:6379" + - "3000:3000" + environment: + - REDIS_ARGS=--requirepass falkordb + - FALKORDB_ARGS=THREAD_COUNT 4 + restart: unless-stopped +``` + +Start FalkorDB: + +```bash +docker-compose up -d +``` + +Stop FalkorDB: + +```bash +docker-compose down +``` + +### Production Setup with Persistence + +For production environments, use the server-only image with data persistence: + +```yaml +version: '3.8' + +services: + falkordb: + image: falkordb/falkordb-server:latest + container_name: falkordb-server + ports: + - "6379:6379" + environment: + - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD:-falkordb} --appendonly yes + - FALKORDB_ARGS=THREAD_COUNT 8 TIMEOUT_MAX 30000 + volumes: + - falkordb_data:/data + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 10s + retries: 3 + +volumes: + falkordb_data: + driver: local +``` + +Start with custom password: + +```bash +FALKORDB_PASSWORD=your-secure-password docker-compose up -d +``` + +### Separate Server and Browser Setup + +Run FalkorDB server and browser as separate containers: + +```yaml +version: '3.8' + +services: + falkordb-server: + image: falkordb/falkordb-server:latest + container_name: falkordb-server + ports: + - "6379:6379" + environment: + - REDIS_ARGS=--requirepass falkordb + - FALKORDB_ARGS=THREAD_COUNT 4 + volumes: + - falkordb_data:/data + restart: unless-stopped + networks: + - falkordb-network + + falkordb-browser: + image: falkordb/falkordb-browser:latest + container_name: falkordb-browser + ports: + - "3000:3000" + environment: + - FALKORDB_URL=redis://falkordb-server:6379 + - FALKORDB_PASSWORD=falkordb + depends_on: + - falkordb-server + restart: unless-stopped + networks: + - falkordb-network + +volumes: + falkordb_data: + driver: local + +networks: + falkordb-network: + driver: bridge +``` + +### Complete Production Setup + +A comprehensive production-ready setup with all recommended configurations: + +```yaml +version: '3.8' + +services: + falkordb: + image: falkordb/falkordb-server:latest + container_name: falkordb-production + ports: + - "6379:6379" + environment: + # Redis Configuration + - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD:-changeme} --appendonly yes --appendfsync everysec --maxmemory 2gb --maxmemory-policy allkeys-lru + # FalkorDB Configuration + - FALKORDB_ARGS=THREAD_COUNT 8 CACHE_SIZE 50 TIMEOUT_MAX 60000 TIMEOUT_DEFAULT 30000 QUERY_MEM_CAPACITY 104857600 + volumes: + - falkordb_data:/data + - ./falkordb-config:/etc/falkordb + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "-a", "$${FALKORDB_PASSWORD:-changeme}", "ping"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + networks: + - falkordb-network + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +volumes: + falkordb_data: + driver: local + +networks: + falkordb-network: + driver: bridge +``` + +## Docker Compose Commands + +Common Docker Compose commands for managing FalkorDB: + +```bash +# Start services in detached mode +docker-compose up -d + +# View logs +docker-compose logs -f + +# View logs for specific service +docker-compose logs -f falkordb + +# Stop services +docker-compose stop + +# Stop and remove containers +docker-compose down + +# Stop and remove containers with volumes (WARNING: deletes data) +docker-compose down -v + +# Restart services +docker-compose restart + +# Check service status +docker-compose ps + +# Execute commands in running container +docker-compose exec falkordb redis-cli +``` + +## Environment Variables + +### REDIS_ARGS +Pass arguments directly to the Redis server: + +```yaml +environment: + - REDIS_ARGS=--requirepass mypassword --maxmemory 1gb --appendonly yes +``` + +Common Redis arguments: +- `--requirepass ` - Set authentication password +- `--appendonly yes` - Enable AOF persistence +- `--appendfsync everysec` - AOF sync frequency +- `--maxmemory ` - Maximum memory limit +- `--maxmemory-policy ` - Eviction policy (e.g., `allkeys-lru`) + +### FALKORDB_ARGS +Pass configuration to FalkorDB module: + +```yaml +environment: + - FALKORDB_ARGS=THREAD_COUNT 4 CACHE_SIZE 25 TIMEOUT_MAX 10000 +``` + +See the [Configuration](/getting-started/configuration) page for all available FalkorDB parameters. + +## Data Persistence + +### Using Named Volumes + +Named volumes are the recommended approach for data persistence: + +```yaml +services: + falkordb: + image: falkordb/falkordb-server:latest + volumes: + - falkordb_data:/data + +volumes: + falkordb_data: +``` + +### Using Bind Mounts + +For specific host directory mapping: + +```yaml +services: + falkordb: + image: falkordb/falkordb-server:latest + volumes: + - ./falkordb-data:/data +``` + +Create the directory first: + +```bash +mkdir -p ./falkordb-data +``` + +## Health Checks + +Add health checks to ensure FalkorDB is running properly: + +```yaml +healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +``` + +With authentication: + +```yaml +healthcheck: + test: ["CMD", "redis-cli", "-a", "yourpassword", "ping"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +``` + +## Networking + +### Custom Networks + +Create isolated networks for better security: + +```yaml +networks: + falkordb-network: + driver: bridge + ipam: + config: + - subnet: 172.25.0.0/16 +``` + +### Expose vs Ports + +Use `expose` for internal communication and `ports` for external access: + +```yaml +services: + falkordb: + image: falkordb/falkordb-server:latest + expose: + - "6379" # Only accessible within Docker network + # Or use ports for external access: + # ports: + # - "6379:6379" +``` + +## Best Practices + +1. **Use Environment Variables**: Store sensitive information like passwords in `.env` files or environment variables: + + Create a `.env` file: + ``` + FALKORDB_PASSWORD=your-secure-password + FALKORDB_THREADS=8 + ``` + + Reference in `docker-compose.yml`: + ```yaml + environment: + - REDIS_ARGS=--requirepass ${FALKORDB_PASSWORD} + - FALKORDB_ARGS=THREAD_COUNT ${FALKORDB_THREADS} + ``` + +2. **Enable Persistence**: Always use volumes for production data: + ```yaml + volumes: + - falkordb_data:/data + ``` + +3. **Set Resource Limits**: Prevent resource exhaustion: + ```yaml + deploy: + resources: + limits: + cpus: '4' + memory: 8G + reservations: + cpus: '2' + memory: 4G + ``` + +4. **Use Health Checks**: Ensure automatic recovery: + ```yaml + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 10s + retries: 3 + ``` + +5. **Configure Logging**: Manage log file sizes: + ```yaml + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + ``` + +6. **Separate Concerns**: Use different images for different purposes: + - Development: `falkordb/falkordb` (with browser) + - Production: `falkordb/falkordb-server` (server only) + +7. **Use Specific Tags**: Pin to specific versions for stability: + ```yaml + image: falkordb/falkordb-server:4.0.0 + ``` + +## Troubleshooting + +### Check Container Logs + +```bash +docker-compose logs falkordb +``` + +### Check Container Status + +```bash +docker-compose ps +``` + +### Test Connection + +```bash +docker-compose exec falkordb redis-cli ping +``` + +### Access Redis CLI + +```bash +docker-compose exec falkordb redis-cli +``` + +### View Running Processes + +```bash +docker-compose top +``` + +### Inspect Configuration + +```bash +docker-compose config +``` + +## Next Steps + +- Learn about [Persistence](/operations/persistence) for data durability +- Set up [Replication](/operations/replication) for high availability +- Configure a [Cluster](/operations/cluster) for scalability +- Review [Configuration](/getting-started/configuration) options +- Deploy to [Kubernetes](/operations/k8s-support) for orchestration diff --git a/operations/index.md b/operations/index.md index 118812ab..dc2fcafe 100644 --- a/operations/index.md +++ b/operations/index.md @@ -15,42 +15,46 @@ The Operations chapter provides essential guides for configuring and managing Fa Table of Contents -## 1. [Configuring Persistence](/operations/persistence) +## 1. [Docker and Docker Compose](/operations/docker) + +Learn how to run FalkorDB using Docker and Docker Compose, with examples for development and production environments including persistence, networking, and configuration options. + +## 2. [Configuring Persistence](/operations/persistence) Learn how to set up FalkorDB with data persistence, ensuring that your data remains intact even after server restarts. -## 2. [Configuring Replication](/operations/replication) +## 3. [Configuring Replication](/operations/replication) Set up replication in FalkorDB to achieve high availability and data redundancy across multiple nodes. -## 3. [Setting Up a Cluster](/operations/cluster) +## 4. [Setting Up a Cluster](/operations/cluster) Discover how to configure a FalkorDB cluster for horizontal scalability and improved fault tolerance, distributing your data across multiple nodes. -## 4. [Deploy FalkorDB to Kubernetes](/operations/k8s_support) +## 5. [Deploy FalkorDB to Kubernetes](/operations/k8s_support) Learn how falkorDB can be deployed on Kubernetes using Helm charts and Docker images. -## 5. [Deploy FalkorDB with KubeBlocks](/operations/kubeblocks) +## 6. [Deploy FalkorDB with KubeBlocks](/operations/kubeblocks) Deploy and manage FalkorDB on Kubernetes using the KubeBlocks operator with automated Day-2 operations, high availability, and comprehensive backup solutions. -## 6. [Deploy FalkorDB on Railway](/operations/railway) +## 7. [Deploy FalkorDB on Railway](/operations/railway) Deploy FalkorDB quickly using verified templates on Railway, a modern platform-as-a-service. Choose between single instance or cluster deployments. -## 7. [OpenTelemetry Integration with FalkorDB-py](/operations/opentelemetry) +## 8. [OpenTelemetry Integration with FalkorDB-py](/operations/opentelemetry) Comprehensive guide for setting up OpenTelemetry observability and tracing with FalkorDB Python applications. -## 8. [FalkorDBLite](/operations/falkordblite) +## 9. [FalkorDBLite](/operations/falkordblite) Self-contained Python interface to FalkorDB with embedded Redis server, ideal for development and testing. -## 9. [Deploy FalkorDB on Lightning.AI](/operations/lightning-ai) +## 10. [Deploy FalkorDB on Lightning.AI](/operations/lightning-ai) Deploy FalkorDB on Lightning.AI to build fast, accurate GenAI applications using advanced RAG with graph databases. -## 10. [Building Docker](/operations/building-docker) +## 11. [Building Docker](/operations/building-docker) Build custom FalkorDB Docker containers from source with platform-specific examples. From efca0aeae7dd54ca85e09af1a9332508e57e31f3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 20:06:39 +0200 Subject: [PATCH 013/107] Fix documentation clarity, broken links, and code examples (#273) * Fix broken links, improve clarity and formatting in documentation --- .wordlist.txt | 3 ++ commands/graph.delete.md | 21 +++++++--- commands/graph.info.md | 12 +++++- cypher/create.md | 24 +++++++----- cypher/delete.md | 32 +++++++++++++-- cypher/indexing.md | 14 +++---- cypher/match.md | 22 ++++++----- cypher/procedures.md | 12 ++++-- cypher/return.md | 56 ++++++++++++++------------ cypher/set.md | 46 +++++++++++++++++----- cypher/unwind.md | 53 +++++++++++++++++++++++-- cypher/where.md | 58 +++++++++++++++------------ cypher/with.md | 33 +++++++++++++--- datatypes.md | 56 +++++++++++++------------- design/result-structure.md | 2 +- getting-started/configuration.md | 12 +++--- getting-started/index.md | 23 ++++++----- index.md | 22 +++++------ migration/redisgraph-to-falkordb.md | 61 +++++++++++++++++++++++++---- operations/persistence.md | 35 +++++++++++------ operations/replication.md | 46 ++++++++++++++++------ 21 files changed, 450 insertions(+), 193 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index b74c2988..052b7c07 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -659,3 +659,6 @@ Addon addon LoadBalancer NodePort +orphaned +replicas +SQL's diff --git a/commands/graph.delete.md b/commands/graph.delete.md index 278a2ed9..1e3a7a18 100644 --- a/commands/graph.delete.md +++ b/commands/graph.delete.md @@ -8,11 +8,20 @@ parent: "Commands" # GRAPH.DELETE -Completely removes the graph and all of its entities. +Completely removes a graph and all of its entities (nodes and relationships). -Arguments: `Graph name` +## Syntax -Returns: `String indicating if operation succeeded or failed.` +``` +GRAPH.DELETE graph_name +``` + +**Arguments:** +- `graph_name` - Name of the graph to delete + +**Returns:** String indicating if the operation succeeded or failed. + +## Examples {% capture shell_0 %} GRAPH.DELETE us_government @@ -36,7 +45,9 @@ graph.delete()?; {% include code_tabs.html id="tabs_0" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %} -Note: To delete a node from the graph (not the entire graph), execute a `MATCH` query and pass the alias to the `DELETE` clause: +## Deleting Individual Nodes + +**Note:** To delete specific nodes or relationships (not the entire graph), use the Cypher `DELETE` clause with a `MATCH` query: {% capture shell_1 %} GRAPH.QUERY DEMO_GRAPH "MATCH (x:Y {propname: propvalue}) DELETE x" @@ -60,5 +71,5 @@ graph.query("MATCH (x:Y {propname: propvalue}) DELETE x")?; {% include code_tabs.html id="tabs_1" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %} -WARNING: When you delete a node, all of the node's incoming/outgoing relationships are also removed. +**⚠️ Warning:** When you delete a node using the Cypher `DELETE` clause, all of the node's incoming and outgoing relationships are also automatically removed. diff --git a/commands/graph.info.md b/commands/graph.info.md index 46972591..d34327b1 100644 --- a/commands/graph.info.md +++ b/commands/graph.info.md @@ -7,7 +7,17 @@ parent: "Commands" # GRAPH.INFO -Returns information and statistics about the current executing commands. +Returns information and statistics about currently running and waiting queries. + +## Syntax + +``` +GRAPH.INFO [RunningQueries | WaitingQueries] +``` + +If no argument is provided, both running and waiting queries are returned. + +## Examples ```sh 127.0.0.1:6379> GRAPH.INFO diff --git a/cypher/create.md b/cypher/create.md index 87bb307e..8870c93a 100644 --- a/cypher/create.md +++ b/cypher/create.md @@ -8,25 +8,31 @@ parent: "Cypher Language" # CREATE -CREATE is used to introduce new nodes and relationships. +The `CREATE` clause is used to introduce new nodes and relationships into the graph. -The simplest example of CREATE would be a single node creation: +## Creating Nodes + +The simplest example creates a single node without any labels or properties: ```sh CREATE (n) ``` -It's possible to create multiple entities by separating them with a comma. +You can create multiple entities by separating them with commas: ```sh CREATE (n),(m) ``` +Create a node with a label and properties: + ```sh CREATE (:Person {name: 'Kurt', age: 27}) ``` -To add relations between nodes, in the following example we first find an existing source node. After it's found, we create a new relationship and destination node. +## Creating Relationships + +To add relationships between nodes, you typically match existing nodes first, then create the relationship. In this example, we find an existing source node and create a new relationship with a new destination node: ```sh GRAPH.QUERY DEMO_GRAPH @@ -35,17 +41,17 @@ WHERE a.name = 'Kurt' CREATE (a)-[:MEMBER]->(:Band {name:'Nirvana'})" ``` -Here the source node is a bounded node, while the destination node is unbounded. +Here the source node `(a:Person)` is matched (bound), while the destination node `(:Band)` is unbound and will be created. -As a result, a new node is created representing the band Nirvana and a new relation connects Kurt to the band. +This query creates a new node representing the band Nirvana and a new `MEMBER` relationship connecting Kurt to the band. -Lastly we create a complete pattern. +## Creating Complete Patterns -All entities within the pattern which are not bounded will be created. +You can create entire graph patterns in a single statement. All entities within the pattern that are not bound (matched) will be created: ```sh GRAPH.QUERY DEMO_GRAPH "CREATE (jim:Person{name:'Jim', age:29})-[:FRIENDS]->(pam:Person {name:'Pam', age:27})-[:WORKS]->(:Employer {name:'Dunder Mifflin'})" ``` -This query will create three nodes and two relationships. +This query creates three nodes (Jim, Pam, and an Employer) and two relationships (FRIENDS and WORKS), establishing a complete graph pattern in one operation. diff --git a/cypher/delete.md b/cypher/delete.md index 85cd77b9..5cf46aa7 100644 --- a/cypher/delete.md +++ b/cypher/delete.md @@ -8,9 +8,13 @@ parent: "Cypher Language" # DELETE -DELETE is used to remove both nodes and relationships. +The `DELETE` clause is used to remove nodes and relationships from the graph. -Note that deleting a node also deletes all of its incoming and outgoing relationships. +## Important Behavior + +**⚠️ Note:** Deleting a node automatically deletes all of its incoming and outgoing relationships. You cannot have orphaned relationships in the graph. + +## Deleting Nodes To delete a node and all of its relationships: @@ -18,10 +22,30 @@ To delete a node and all of its relationships: GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person {name:'Jim'}) DELETE p" ``` -To delete relationship: +## Deleting Relationships + +To delete specific relationships: ```sh GRAPH.QUERY DEMO_GRAPH "MATCH (:Person {name:'Jim'})-[r:FRIENDS]->() DELETE r" ``` -This query will delete all `friend` outgoing relationships from the node with the name 'Jim'. \ No newline at end of file +This query deletes all outgoing `FRIENDS` relationships from the node with name 'Jim', while keeping the nodes intact. + +## Common Patterns + +### Delete all nodes and relationships in a graph + +```sh +GRAPH.QUERY DEMO_GRAPH "MATCH (n) DETACH DELETE n" +``` + +The `DETACH DELETE` automatically removes all relationships before deleting the node. + +### Conditional deletion + +```sh +GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE p.age < 18 DELETE p" +``` + +Deletes all Person nodes where age is less than 18. \ No newline at end of file diff --git a/cypher/indexing.md b/cypher/indexing.md index d6b97939..78342e63 100644 --- a/cypher/indexing.md +++ b/cypher/indexing.md @@ -646,23 +646,23 @@ let result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Ch To delete the full-text index for a specific relation label, use: {% capture shell_18 %} -GRAPH.QUERY DEMO_GRAPH "CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)" +GRAPH.QUERY DEMO_GRAPH "DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)" {% endcapture %} {% capture python_18 %} -graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)") +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)") {% endcapture %} {% capture javascript_18 %} -await graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); +await graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); {% endcapture %} {% capture java_18 %} -graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); {% endcapture %} {% capture rust_18 %} -graph.query("CALL DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?; +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?; {% endcapture %} {% include code_tabs.html id="fulltext_relation_drop_tabs" shell=shell_18 python=python_18 javascript=javascript_18 java=java_18 rust=rust_18 %} @@ -681,8 +681,8 @@ CREATE VECTOR INDEX FOR ON OPTIONS The options are: ``` { - dimension: INT, // Requiered, length of the vector to be indexed - similarityFunction: STRING, // Requiered, currently only euclidean or cosine are allowed + dimension: INT, // Required, length of the vector to be indexed + similarityFunction: STRING, // Required, currently only euclidean or cosine are allowed M: INT, // Optional, maximum number of outgoing edges per node. default 16 efConstruction: INT, // Optional, number of candidates during construction. default 200 efRuntime: INT // Optional, number of candidates during search. default 10 diff --git a/cypher/match.md b/cypher/match.md index 588c8fe3..6976a83d 100644 --- a/cypher/match.md +++ b/cypher/match.md @@ -8,16 +8,19 @@ parent: "Cypher Language" # MATCH -Match describes the relationship between queried entities, using ascii art to represent pattern(s) to match against. +The `MATCH` clause describes the relationship between queried entities using ASCII art to represent pattern(s) to match against. -Nodes are represented by parentheses `()`, -and Relationships are represented by brackets `[]`. +**Syntax Overview:** +- Nodes are represented by parentheses `()` +- Relationships are represented by brackets `[]` +- Each graph entity (node/relationship) can contain an alias, a label/relationship type, and filters, but all are optional -Each graph entity node/relationship can contain an alias and a label/relationship type, but both can be left empty if necessary. +**Entity Structure:** `alias:label {filters}` -Entity structure: `alias:label {filters}`. - -Alias, label/relationship type, and filters are all optional. +Where: +- `alias` - Optional variable name to reference the entity +- `label` - Optional label for nodes or type for relationships +- `{filters}` - Optional property filters Example: @@ -35,10 +38,9 @@ Example: `Movie` destination node is of "type" movie. -`{title:"straight outta compton"}` requires the node's title attribute to equal "straight outta compton". +`{title:"straight outta compton"}` filters for nodes where the title property equals "straight outta compton". -In this example, we're interested in actor entities which have the relation "act" with **the** entity representing the -"straight outta compton" movie. +In this example, we're querying for actor entities that have an "ACT" relationship with the movie entity "straight outta compton". It is possible to describe broader relationships by composing a multi-hop query such as: diff --git a/cypher/procedures.md b/cypher/procedures.md index d8305e0e..5f501c50 100644 --- a/cypher/procedures.md +++ b/cypher/procedures.md @@ -8,19 +8,25 @@ parent: "Cypher Language" # Procedures -Procedures are invoked using the syntax: +Procedures are functions that can be called from within Cypher queries using the `CALL` syntax. + +## Syntax + +Basic procedure call: ```sh GRAPH.QUERY social "CALL db.labels()" ``` -Or the variant: +With explicit `YIELD` to select specific return values: ```sh GRAPH.QUERY social "CALL db.labels() YIELD label" ``` -YIELD modifiers are only required if explicitly specified; by default the value in the 'Yields' column will be emitted automatically. +**Note:** The `YIELD` clause is optional. When omitted, all values listed in the 'Yields' column are returned automatically. + +## Available Procedures | Procedure | Arguments | Yields | Description | | ------- | :------- | :------- | :----------- | diff --git a/cypher/return.md b/cypher/return.md index 30f9e1be..9543e3d8 100644 --- a/cypher/return.md +++ b/cypher/return.md @@ -8,51 +8,57 @@ parent: "Cypher Language" # RETURN -In its simple form, Return defines which properties the returned result-set will contain. +The `RETURN` clause defines which properties and values the result-set will contain. -Its structure is a list of `alias.property` separated by commas. +## Basic Usage -For convenience, it's possible to specify the alias only when you're interested in every attribute an entity possesses, -and don't want to specify each attribute individually. For example: +The basic structure is a comma-separated list of `alias.property` expressions: + +```sh +RETURN person.name, person.age +``` + +For convenience, you can specify just the alias to return all properties of an entity: ```sh RETURN movie.title, actor ``` -Use the DISTINCT keyword to remove duplications within the result-set: +## Removing Duplicates + +Use the `DISTINCT` keyword to remove duplicate values from the result-set: ```sh RETURN DISTINCT friend_of_friend.name ``` -In the above example, suppose we have two friends, Joe and Miesha, -and both know Dominick. +For example, if you have two friends (Joe and Miesha) who both know Dominick, `DISTINCT` ensures that Dominick appears only once in the final result set. -DISTINCT will make sure Dominick will only appear once -in the final result set. +## Aggregations -Return can also be used to aggregate data, similar to group by in SQL. +The `RETURN` clause can also aggregate data, similar to SQL's GROUP BY functionality. -Once an aggregation function is added to the return -list, all other "none" aggregated values are considered as group keys, for example: +When an aggregation function is used in the RETURN list, all non-aggregated values become implicit grouping keys: ```sh RETURN movie.title, MAX(actor.age), MIN(actor.age) ``` -Here we group data by movie title and for each movie, and we find its youngest and oldest actor age. +This query groups data by movie title and, for each movie, returns the youngest and oldest actor ages. -## Aggregations +### Supported Aggregation Functions + +| Function | Description | +|----------|-------------| +| `avg` | Calculate average of numeric values | +| `collect` | Collect values into a list | +| `count` | Count number of values | +| `max` | Find maximum value | +| `min` | Find minimum value | +| `percentileCont` | Calculate continuous percentile | +| `percentileDisc` | Calculate discrete percentile | +| `stDev` | Calculate standard deviation | +| `sum` | Calculate sum of numeric values | -Supported aggregation functions include: - -* `avg` -* `collect` -* `count` -* `max` -* `min` -* `percentileCont` -* `percentileDisc` -* `stDev` -* `sum` \ No newline at end of file +For detailed information on aggregation functions, see the [Functions documentation](/cypher/functions#aggregating-functions). \ No newline at end of file diff --git a/cypher/set.md b/cypher/set.md index 294d0965..6b7256a8 100644 --- a/cypher/set.md +++ b/cypher/set.md @@ -8,15 +8,19 @@ parent: "Cypher Language" # SET -SET is used to create or update properties on nodes and relationships. +The `SET` clause is used to create or update properties on nodes and relationships. -To set a property on a node, use `SET`. +## Setting a Single Property + +To set a property on a node: ```sh GRAPH.QUERY DEMO_GRAPH "MATCH (n { name: 'Jim' }) SET n.name = 'Bob'" ``` -If you want to set multiple properties in one go, simply separate them with a comma to set multiple properties using a single SET clause. +## Setting Multiple Properties + +You can set multiple properties in a single `SET` clause by separating them with commas: ```sh GRAPH.QUERY DEMO_GRAPH @@ -24,7 +28,13 @@ GRAPH.QUERY DEMO_GRAPH SET n.age = 33, n.name = 'Bob'" ``` -The same can be accomplished by setting the graph entity variable to a map: +## Setting Properties from a Map + +You can set properties using a map. There are two operators with different behaviors: + +### Replace All Properties (`=`) + +Replaces **all** existing properties with the map properties: ```sh GRAPH.QUERY DEMO_GRAPH @@ -32,9 +42,23 @@ GRAPH.QUERY DEMO_GRAPH SET n = {age: 33, name: 'Bob'}" ``` -Using `=` in this way replaces all of the entity's previous properties, while `+=` will only set the properties it explicitly mentions. +**Result:** The node will have only the properties `age` and `name`. Any other existing properties are removed. -In the same way, the full property set of a graph entity can be assigned or merged: +### Merge Properties (`+=`) + +Updates only the specified properties while keeping other existing properties: + +```sh +GRAPH.QUERY DEMO_GRAPH +"MATCH (n { name: 'Jim', age:32 }) +SET n += {age: 33}" +``` + +**Result:** The node's `age` is updated to 33, but `name` and any other properties remain unchanged. + +## Copying Properties Between Entities + +You can copy all properties from one entity to another: ```sh GRAPH.QUERY DEMO_GRAPH @@ -42,10 +66,14 @@ GRAPH.QUERY DEMO_GRAPH SET jim = pam" ``` -After executing this query, the `jim` node will have the same property set as the `pam` node. +After executing this query, the `jim` node will have exactly the same properties as the `pam` node (all of Jim's original properties are replaced). + +## Removing Properties -To remove a node's property, simply set property value to NULL. +To remove a property, set its value to `NULL`: ```sh GRAPH.QUERY DEMO_GRAPH "MATCH (n { name: 'Jim' }) SET n.name = NULL" -``` \ No newline at end of file +``` + +This removes the `name` property from the node entirely. \ No newline at end of file diff --git a/cypher/unwind.md b/cypher/unwind.md index 58557c50..c474e29f 100644 --- a/cypher/unwind.md +++ b/cypher/unwind.md @@ -8,16 +8,61 @@ parent: "Cypher Language" # UNWIND -The UNWIND clause breaks down a given list into a sequence of records; each contains a single element in the list. +The `UNWIND` clause transforms a list into individual rows, creating one row for each element in the list. -The order of the records preserves the original list order. +## Behavior + +- Each element in the list becomes a separate row +- The order of rows preserves the original list order +- Useful for processing lists, creating multiple entities, or parameter expansion + +## Basic Example + +Create a node with an array property: + +```sh +GRAPH.QUERY DEMO_GRAPH "CREATE (p {array:[1,2,3]})" +``` + +Unwind the array into individual rows: + +```sh +GRAPH.QUERY DEMO_GRAPH "MATCH (p) UNWIND p.array AS y RETURN y" +``` + +**Result:** +``` +y +1 +2 +3 +``` + +## Practical Examples + +### Create Multiple Nodes from a List + +```sh +GRAPH.QUERY DEMO_GRAPH +"UNWIND ['Alice', 'Bob', 'Charlie'] AS name +CREATE (:Person {name: name})" +``` + +### Process Nested Data ```sh GRAPH.QUERY DEMO_GRAPH -"CREATE (p {array:[1,2,3]})" +"WITH [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}] AS people +UNWIND people AS person +CREATE (:Person {name: person.name, age: person.age})" ``` +### Combine with Other Clauses + ```sh GRAPH.QUERY DEMO_GRAPH -"MATCH (p) UNWIND p.array AS y RETURN y" +"MATCH (p:Person) +WITH collect(p.name) AS names +UNWIND names AS name +RETURN name ORDER BY name" ``` \ No newline at end of file diff --git a/cypher/where.md b/cypher/where.md index a2f8fc97..645675d8 100644 --- a/cypher/where.md +++ b/cypher/where.md @@ -8,26 +8,30 @@ parent: "Cypher Language" # WHERE -This clause is not mandatory, but if you want to filter results, you can specify your predicates here. +The `WHERE` clause is optional and is used to filter results based on predicates (conditions). -Supported operations: +## Supported Comparison Operators -* `=` -* `<>` -* `<` -* `<=` -* `>` -* `>=` -* `CONTAINS` -* `ENDS WITH` -* `IN` -* `STARTS WITH` +| Operator | Description | +|----------|-------------| +| `=` | Equal to | +| `<>` | Not equal to | +| `<` | Less than | +| `<=` | Less than or equal to | +| `>` | Greater than | +| `>=` | Greater than or equal to | +| `CONTAINS` | String contains substring | +| `ENDS WITH` | String ends with substring | +| `IN` | Value is in list | +| `STARTS WITH` | String starts with substring | -Predicates can be combined using AND / OR / NOT. +## Combining Predicates -Be sure to wrap predicates within parentheses to control precedence. +Predicates can be combined using the logical operators `AND`, `OR`, and `NOT`. -Examples: +Use parentheses to control precedence when combining multiple predicates. + +### Examples: ```sql WHERE (actor.name = "john doe" OR movie.rating > 8.8) AND movie.votes <= 250) @@ -37,38 +41,42 @@ WHERE (actor.name = "john doe" OR movie.rating > 8.8) AND movie.votes <= 250) WHERE actor.age >= director.age AND actor.age > 32 ``` -It is also possible to specify equality predicates within nodes using the curly braces as such: +## Inline Property Filters + +You can specify equality predicates directly within node patterns using curly braces: ```sql (:President {name:"Jed Bartlett"})-[:WON]->(:State) ``` -Here we've required that the president node's name will have the value "Jed Bartlett". +This requires that the president node's `name` property equals "Jed Bartlett". + +Inline predicates are functionally equivalent to predicates specified in the WHERE clause. -There's no difference between inline predicates and predicates specified within the WHERE clause. +## Pattern Predicates -It is also possible to filter on graph patterns. The following queries, which return all presidents and the states they won in, produce the same results: +You can also filter based on graph patterns. These two queries are equivalent and both return presidents and the states they won: ```sh MATCH (p:President), (s:State) WHERE (p)-[:WON]->(s) RETURN p, s ``` -and - ```sh MATCH (p:President)-[:WON]->(s:State) RETURN p, s ``` -Pattern predicates can be also negated and combined with the logical operators AND, OR, and NOT. The following query returns all the presidents that did not win in the states where they were governors: +Pattern predicates can be negated and combined with logical operators. This query returns presidents who did not win in states where they were governors: ```sh -MATCH (p:President), (s:State) WHERE NOT (p)-[:WON]->(s) AND (p)->[:governor]->(s) RETURN p, s +MATCH (p:President), (s:State) WHERE NOT (p)-[:WON]->(s) AND (p)-[:GOVERNOR]->(s) RETURN p, s ``` -Nodes can also be filtered by label: +## Label Filtering + +Nodes can be filtered by label in the WHERE clause: ```sh MATCH (n)-[:R]->() WHERE n:L1 OR n:L2 RETURN n ``` -When possible, it is preferable to specify the label in the node pattern of the MATCH clause. +**Best Practice:** When possible, specify labels directly in the node pattern of the MATCH clause for better performance. diff --git a/cypher/with.md b/cypher/with.md index 9844046b..13e03337 100644 --- a/cypher/with.md +++ b/cypher/with.md @@ -8,20 +8,43 @@ parent: "Cypher Language" # WITH -The WITH clause allows parts of queries to be independently executed and have their results handled uniquely. +The `WITH` clause allows you to chain query parts together, passing results from one part to the next. This enables complex query composition and data manipulations. -This allows for more flexible query composition as well as data manipulations that would otherwise not be possible in a single query. +## Use Cases -If, for example, we wanted to find all children in our graph who are above the average age of all people: +`WITH` is useful for: +- Chaining multiple query parts together +- Performing intermediate aggregations +- Filtering or transforming results before the next query part +- Using query modifiers (`DISTINCT`, `ORDER BY`, `LIMIT`, `SKIP`) mid-query + +## Example: Filtering by Aggregated Values + +Find all children above the average age of all people: ```sh GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WITH AVG(p.age) AS average_age MATCH (:Person)-[:PARENT_OF]->(child:Person) WHERE child.age > average_age return child ``` -This also allows us to use modifiers like `DISTINCT`, `SKIP`, `LIMIT`, and `ORDER` that otherwise require `RETURN` clauses. +## Example: Using Modifiers Mid-Query + +You can use query modifiers with `WITH` to filter or sort before continuing: ```sh GRAPH.QUERY DEMO_GRAPH "MATCH (u:User) WITH u AS nonrecent ORDER BY u.lastVisit LIMIT 3 SET nonrecent.should_contact = true" -``` \ No newline at end of file +``` + +This query: +1. Matches all users +2. Orders them by last visit (oldest first) +3. Limits to the 3 least recent visitors +4. Sets a flag on those users + +## Key Points + +- `WITH` acts like a pipeline between query parts +- Variables not included in `WITH` are not available in subsequent parts +- You can rename variables using `AS` in the `WITH` clause +- Aggregations in `WITH` cause implicit grouping (like `RETURN`) \ No newline at end of file diff --git a/datatypes.md b/datatypes.md index 61b882b1..6ca4c883 100644 --- a/datatypes.md +++ b/datatypes.md @@ -103,15 +103,13 @@ Since we cannot reason broadly about unknown values, `null` is an important part Unlike all other scalars, `null` cannot be stored as a property value. ## Temporal Types -FalkorDB supports the following temporal types that allow modeling and querying time-related data: - -## 1. [Date](#Date) -## 2. [Time](#Time) - -## 3. [DateTime](#DateTime) +FalkorDB supports the following temporal types that allow modeling and querying time-related data: -## 4. [Duration](#Duration) +1. [Date](#date) - Calendar dates (YYYY-MM-DD) +2. [Time](#time) - Time of day (HH:MM:SS) +3. [DateTime](#datetime) - Combined date and time +4. [Duration](#duration) - Time intervals These types follow the ISO 8601 standard and can be used in properties, parameters, and expressions. @@ -119,16 +117,17 @@ These types follow the ISO 8601 standard and can be used in properties, paramete Represents a calendar date in the format YYYY-MM-DD. -Purpose -Use Date to store and compare dates without time information, e.g. birth dates, due dates, or deadlines. +**Purpose:** +Use `Date` to store and compare dates without time information, such as birth dates, due dates, or deadlines. + +**Example:** ```cypher CREATE (:Event { name: "Conference", date: date("2025-09-15") }) ``` -#### Interactions -* Compare using operators (=, <, >, etc.) - +**Interactions:** +* Compare using operators (`=`, `<`, `>`, etc.) * Extract components using functions: ```cypher @@ -139,16 +138,18 @@ RETURN date("2025-09-15").day // 15 ### Time -Represents a time of day, in the format hh:mm:ss. +Represents a time of day in the format HH:MM:SS. -Purpose -Use Time to store specific times (e.g. store hours, alarm times) without date context. +**Purpose:** +Use `Time` to store specific times (e.g., store hours, alarm times) without date context. + +**Example:** ```cypher CREATE (:Reminder { msg: "Wake up!", at: localtime("07:00:00") }) ``` -#### Interactions +**Interactions:** * Compare time values: @@ -168,18 +169,17 @@ RETURN localtime("15:45:20").second // 20 Represents a point in time, combining both date and time. Format: YYYY-MM-DDTHH:MM:SS. -Purpose -Use DateTime when both date and time are relevant, e.g. logging events, scheduling, timestamps. +**Purpose:** +Use `DateTime` when both date and time are relevant, such as logging events, scheduling, or timestamps. -Example +**Example:** ```cypher CREATE (:Log { message: "System rebooted", at: localdatetime("2025-06-29T13:45:00") }) ``` -#### Interactions - -* Compare with other DateTime values +**Interactions:** +* Compare with other `DateTime` values * Extract parts: ```cypher @@ -187,7 +187,7 @@ RETURN localdatetime("2025-06-29T13:45:00").year // 2025 RETURN localdatetime("2025-06-29T13:45:00").hour // 13 ``` -* Use localdatetime() with no arguments to get the current system time: +* Use `localdatetime()` with no arguments to get the current system time: ```cypher RETURN localdatetime() @@ -195,17 +195,17 @@ RETURN localdatetime() ### Duration -Represents a span of time. Format: P[n]Y[n]M[n]DT[n]H[n]M[n]S (ISO 8601 Duration). +Represents a span of time in ISO 8601 Duration format: `P[n]Y[n]M[n]DT[n]H[n]M[n]S` -Purpose -Use Duration to represent intervals, e.g. "3 days", "2 hours", or "1 year and 6 months". +**Purpose:** +Use `Duration` to represent time intervals, such as "3 days", "2 hours", or "1 year and 6 months". -Example +**Example:** ```cypher CREATE (:Cooldown { period: duration("P3DT12H") }) ``` -#### Interactions +**Interactions:** * Add/subtract durations with dates or datetimes: diff --git a/design/result-structure.md b/design/result-structure.md index 19092c3d..5d25c83c 100644 --- a/design/result-structure.md +++ b/design/result-structure.md @@ -9,7 +9,7 @@ redirect_from: # Result Set Structure -This document describes the format FalkorDB uses to print data when accessed through the `redis-cli` utility. The [language-specific clients](/clients) retrieve data in a more succinct format, and provide their own functionality for printing result sets. +This document describes the format FalkorDB uses to print data when accessed through the `redis-cli` utility. The [language-specific clients](/getting-started/clients) retrieve data in a more succinct format, and provide their own functionality for printing result sets. ## Top-level members diff --git a/getting-started/configuration.md b/getting-started/configuration.md index 3c005d70..f877c785 100644 --- a/getting-started/configuration.md +++ b/getting-started/configuration.md @@ -14,7 +14,7 @@ redirect_from: FalkorDB supports [Redis configuration](https://redis.io/docs/management/config/) and multiple module configuration parameters. Some of these parameters can only be set at load-time, while other parameters can be set either on load-time or on run-time. -For example the following will run the server with global authentication password and 4 threads. +For example, the following command will run the server with global authentication password and 4 threads: ```sh docker run -p 6379:6379 -p 3000:3000 -it -e REDIS_ARGS="--requirepass falkordb" -e FALKORDB_ARGS="THREAD_COUNT 4" --rm falkordb/falkordb:latest @@ -25,9 +25,11 @@ docker run -p 6379:6379 -p 3000:3000 -it -e REDIS_ARGS="--requirepass falkordb" > docker run -p 6379:6379 -it -e REDIS_ARGS="--requirepass falkordb" -e FALKORDB_ARGS="THREAD_COUNT 4" --rm falkordb/falkordb-server:latest > ``` -## Setting configuration parameters on module load +## Setting Configuration Parameters on Module Load -Setting configuration parameters at load-time is done by appending arguments after the `--loadmodule` argument when starting a server from the command line or after the `loadmodule` directive in a Redis config file. For example: +Configuration parameters can be set at load-time by appending arguments after the `--loadmodule` argument when starting a server from the command line or after the `loadmodule` directive in a Redis config file. + +### Examples In [redis.conf](https://redis.io/docs/manual/config/): @@ -59,9 +61,9 @@ Or for production use: docker run -p 6379:6379 -it -e FALKORDB_ARGS="[OPT VAL]" --rm falkordb/falkordb-server:latest ``` -## Setting configuration parameters at run-time (for supported parameters) +## Setting Configuration Parameters at Run-Time (for Supported Parameters) -FalkorDB exposes the `GRAPH.CONFIG` command to allowing for the setting and retrieval of configuration parameters at run-time. +FalkorDB exposes the `GRAPH.CONFIG` command for setting and retrieving configuration parameters at run-time. To set the value of a configuration parameter at run-time (for supported parameters), simply run: diff --git a/getting-started/index.md b/getting-started/index.md index ff255f24..a1a65987 100644 --- a/getting-started/index.md +++ b/getting-started/index.md @@ -12,8 +12,7 @@ redirect_from: # Getting Started with FalkorDB -This guide will walk you through setting up FalkorDB, modeling a social network as a graph, -and accessing it using the [FalkorDB Python client](/getting-started/clients) with [Cypher](/cypher). +This guide will walk you through setting up FalkorDB, modeling a social network as a graph, and accessing it using one of the [FalkorDB client libraries](/getting-started/clients) with the [Cypher](/cypher) query language. --- @@ -58,15 +57,19 @@ Let's create a simple graph for a social network where: ### Graph Schema -| Node Type | Properties | -|-----------|--------------------------| -| User | `id`, `name`, `email` | -| Post | `id`, `content`, `date` | +**Node Types:** -| Relationship Type | Start Node | End Node | Properties | -|-------------------|------------|----------|--------------| -| FRIENDS_WITH | User | User | `since` | -| CREATED | User | Post | `time` | +| Node Type | Properties | Description | +|-----------|--------------------------|---------------------------------------| +| User | `id`, `name`, `email` | Represents a user in the social network | +| Post | `id`, `content`, `date` | Represents a post created by a user | + +**Relationship Types:** + +| Relationship Type | Start Node | End Node | Properties | Description | +|-------------------|------------|----------|--------------|------------------------------------------| +| FRIENDS_WITH | User | User | `since` | Indicates friendship between two users | +| CREATED | User | Post | `time` | Connects a user to their created posts | ![FalkorDB-Model a Social Network as a Graph](https://github.com/user-attachments/assets/57d9b837-661e-4500-a9f2-88e754382d29) diff --git a/index.md b/index.md index fd5bdd0a..fbe9aba1 100644 --- a/index.md +++ b/index.md @@ -17,33 +17,33 @@ permalink: / ### About FalkorDB FalkorDB delivers an **accurate, multi-tenant RAG solution powered by a low-latency, scalable graph database technology.** -* Our solution is purpose-built for development teams working with complex, interconnected data—whether structured or unstructured—in real-time or interactive user environments. +* Our solution is purpose-built for development teams working with complex, interconnected data—whether structured or unstructured—in real-time or interactive user environments. -* The system supports the OpenCypher query language with proprietary enhancements that streamline interactions with graph data, and its efficient graph traversal and query capabilities render it well-suited for production environments. +* The system supports the OpenCypher query language with proprietary enhancements that streamline interactions with graph data. Its efficient graph traversal and query capabilities make it well-suited for production environments. ### Choose Your Path -* **Graph Path:** If you're interested in utilizing FalkorDB as a property graph database with OpenCypher support, continue with the sections below. -* **GraphRAG Path:** If you're aiming to implement advanced graph reasoning and generative AI tasks, jump directly to the [GraphRAG SDK](https://github.com/FalkorDB/GraphRAG-SDK) section [1]. +* **Graph Database Path:** If you're interested in using FalkorDB as a property graph database with OpenCypher support, continue with the sections below. +* **GraphRAG Path:** If you're aiming to implement advanced graph reasoning and generative AI tasks, explore our [GenAI Tools](/genai-tools) section, starting with the [GraphRAG SDK](/genai-tools/graphrag-sdk). ## Primary Features * Adopts the [Property Graph Model](https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc) * Supports [OpenCypher](http://www.opencypher.org/) query language with proprietary extensions -* Offers [Full-Text Search](/cypher/indexing#full-text-indexing), [Vector Similarity](/cypher/indexing#vector-indexing) & [Numeric indexing](/cypher/indexing). -* Interacts via either [RESP](https://redis.io/docs/reference/protocol-spec/) and [Bolt](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) protocols -* Graphs represented as sparse adjacency matrices -* Supports GraphRAG with the [GraphRAG SDK](https://github.com/FalkorDB/GraphRAG-SDK) for advanced graph reasoning and generative AI tasks. +* Offers [Full-Text Search](/cypher/indexing#full-text-indexing), [Vector Similarity](/cypher/indexing#vector-indexing), and [Range indexing](/cypher/indexing) for efficient querying +* Supports both [RESP](https://redis.io/docs/reference/protocol-spec/) and [Bolt](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) protocols for flexible connectivity +* Uses sparse adjacency matrix representation for efficient graph storage +* Provides GraphRAG capabilities through the [GraphRAG SDK](/genai-tools/graphrag-sdk) for advanced graph reasoning and generative AI tasks ## Get Started -Launch an instance using docker, or use [FalkorDB Clouds](https://app.falkordb.cloud) +Launch an instance using Docker, or use [FalkorDB Cloud](https://app.falkordb.cloud) ```sh docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest ``` -Once loaded you can interact with FalkorDB using any of the supported [client libraries](/clients) +Once loaded you can interact with FalkorDB using any of the supported [client libraries](/getting-started/clients) Here we'll use [FalkorDB Python client](https://pypi.org/project/FalkorDB/) to create a small graph representing a subset of motorcycle riders and teams taking part in the MotoGP league, once created we'll start querying our data. @@ -238,7 +238,7 @@ For additional demos please see visit [Demos](https://github.com/FalkorDB/demos) ## Client libraries Language-specific clients have been written by the community and the FalkorDB team. -The full list and links can be found on the [Clients](/clients) page. +The full list and links can be found on the [Client Libraries](/getting-started/clients) page. ## Data import diff --git a/migration/redisgraph-to-falkordb.md b/migration/redisgraph-to-falkordb.md index 89afee98..92279041 100644 --- a/migration/redisgraph-to-falkordb.md +++ b/migration/redisgraph-to-falkordb.md @@ -7,12 +7,34 @@ redirect_from: - /redisgraph-to-falkordb --- -# FalkorDB is compatible with RedisGraph RDB files. +# RedisGraph to FalkorDB Migration -For the migration, execute the following steps: +FalkorDB is fully compatible with RedisGraph RDB (Redis Database) files, making migration straightforward. -1. Get the latest RDB file from your RedisGraph instance. Ensure you call SAVE or BGSAVE to capture the latest data snapshot. -2. Load the RDB file into FalkorDB. When using the FalkorDB Docker image, use the following command: +## Migration Steps + +### Step 1: Create RDB Snapshot from RedisGraph + +Create a snapshot of your RedisGraph database using the `SAVE` or `BGSAVE` command: + +```bash +# Connect to your RedisGraph instance +redis-cli + +# Create snapshot (blocks server during save) +SAVE + +# Or create snapshot in background (recommended for production) +BGSAVE +``` + +This creates a `dump.rdb` file in your Redis data directory. + +### Step 2: Load RDB File into FalkorDB + +#### Using Docker + +When using the FalkorDB Docker image, mount your RDB file and configure Redis to load it: ```bash docker run -it -p 6379:6379 -v $(pwd):/data -e REDIS_ARGS="--dir /data --dbfilename dump.rdb" falkordb/falkordb @@ -21,8 +43,31 @@ For the migration, execute the following steps: Make sure to place the RDB file in the directory mapped to the Docker volume. For FalkorDB Cloud, follow the cloud provider’s instructions for uploading and restoring from an RDB file. -## Additional Tips: +**Important:** Ensure your `dump.rdb` file is placed in the directory mapped to the Docker volume (`$(pwd)` in the example above). + +#### Using FalkorDB Cloud + +For FalkorDB Cloud deployments, follow the cloud provider's instructions for uploading and restoring from an RDB file. + +## Verification + +After loading the RDB file, verify your data: + +```bash +# Connect to FalkorDB +redis-cli + +# List all graphs +GRAPH.LIST + +# Query a graph to verify data +GRAPH.QUERY your_graph_name "MATCH (n) RETURN count(n)" +``` + +## Best Practices -* Verify the integrity of the RDB file before and after transfer. -* Consider downtime and data consistency during the migration process. -* Test the migration process in a staging environment before applying it to production. +* **Verify RDB Integrity:** Check the RDB file integrity before and after transfer +* **Plan for Downtime:** Consider downtime requirements and data consistency during migration +* **Test First:** Always test the migration in a staging environment before production +* **Backup:** Keep backups of both the source RedisGraph data and the RDB file +* **Monitor:** After migration, monitor FalkorDB performance and verify queries work correctly diff --git a/operations/persistence.md b/operations/persistence.md index f88bb32d..4af894e5 100644 --- a/operations/persistence.md +++ b/operations/persistence.md @@ -39,24 +39,31 @@ You can now run FalkorDB with the volume attached: docker run -d --name falkordb -v falkordb_data:/var/lib/falkordb/data -p 6379:6379 falkordb/falkordb ``` -In this configuration: - -The -v falkordb_data:/var/lib/falkordb/data flag mounts the volume to the /var/lib/falkordb/data directory inside the container. -FalkorDB will use the /var/lib/falkordb/data directory by default. +**Configuration details:** +- The `-v falkordb_data:/var/lib/falkordb/data` flag mounts the volume to the `/var/lib/falkordb/data` directory inside the container +- FalkorDB stores its data in the `/var/lib/falkordb/data` directory by default ## Step 2: Verifying the Setup -To verify that your setup is working correctly: +To verify that persistence is working correctly, follow these steps: -* Persistence Check: Stop the FalkorDB container and start it again. The data should persist across restarts. +### 2.1 Create Test Data ```bash -redis-cli graph.query mygraph "CREATE (:Database {name:'falkordb'})" +redis-cli GRAPH.QUERY mygraph "CREATE (:Database {name:'falkordb'})" +``` + +### 2.2 Restart Container +```bash docker stop falkordb docker start falkordb +``` -redis-cli graph.query mygraph "MATCH (n) return n" +### 2.3 Verify Data Persists + +```bash +redis-cli GRAPH.QUERY mygraph "MATCH (n) RETURN n" # Output should be: # 1) 1) "n" # 2) 1) 1) 1) 1) "id" @@ -70,9 +77,15 @@ redis-cli graph.query mygraph "MATCH (n) return n" # 2) "Query internal execution time: 0.122645 milliseconds" ``` -## Conclusion +## Best Practices + +- **Backup Regularly:** Even with persistence, maintain regular backups of your data +- **Monitor Disk Space:** Ensure sufficient disk space is available for the volume +- **Use Named Volumes:** Named volumes are easier to manage than bind mounts + +## Next Steps -With persistence configured, FalkorDB is now set up for reliable data storage that remains intact across container restarts. This setup ensures that your data is consistently saved, providing a stable and dependable environment for your applications. +With persistence configured, FalkorDB is now set up for reliable data storage that remains intact across container restarts. -If you're interested in learning more about high availability and replication, be sure to check out the [replication](/operations/replication) chapter in the documentation. +For high availability and data redundancy, explore [Replication](/operations/replication) to set up multiple FalkorDB instances. diff --git a/operations/replication.md b/operations/replication.md index 47bdeef6..b9c12776 100644 --- a/operations/replication.md +++ b/operations/replication.md @@ -22,8 +22,9 @@ Before you begin, ensure you have the following: ## Step 1: Configuring Replication -Replication ensures that your data is available across multiple FalkorDB instances. You can configure one instance as the master and others as replicas. -For that to work with Docker, we need to first set up a network. +Replication ensures that your data is available across multiple FalkorDB instances. You configure one instance as the primary (master) and others as replicas. + +To enable communication between FalkorDB containers, we first need to set up a Docker network. ### 1.1 Creating a Network @@ -46,7 +47,7 @@ docker run -d \ falkordb/falkordb ``` -This instance will be created in the Standalone mode, as master. +This instance runs in standalone mode and will serve as the primary (master) node. ### 1.2 Setting up the Replica Instance @@ -73,19 +74,23 @@ This command tells the replica to replicate data from the master instance. ## Step 2: Verifying the Setup -To verify that your setup is working correctly: +To verify that replication is working correctly: -* Replication Check: Insert some data into the master instance and check if it is available in the replica. +### 2.1 Insert Data on Master ```bash # Connect to the master -docker exec -it falkordb-master /bin/bash -redis-cli graph.query mygraph "CREATE (:Database {name:'falkordb'})" +docker exec -it falkordb-master redis-cli +GRAPH.QUERY mygraph "CREATE (:Database {name:'falkordb'})" exit +``` + +### 2.2 Verify Data on Replica +```bash # Connect to the replica -docker exec -it falkordb-replica1 /bin/bash -redis-cli graph.ro_query mygraph "MATCH (n) return n" +docker exec -it falkordb-replica1 redis-cli +GRAPH.RO_QUERY mygraph "MATCH (n) RETURN n" # Output should be: # 1) 1) "n" # 2) 1) 1) 1) 1) "id" @@ -99,8 +104,25 @@ redis-cli graph.ro_query mygraph "MATCH (n) return n" # 2) "Query internal execution time: 0.122645 milliseconds" ``` -## Conclusion +**Expected output:** The data created on the master should be available on the replica. + +## Best Practices + +- **Read-Only Queries on Replicas:** Use `GRAPH.RO_QUERY` for read operations on replicas to prevent accidental writes +- **Monitor Replication Lag:** Check replication status regularly using Redis `INFO replication` command +- **Multiple Replicas:** Configure multiple replicas for better read scalability and redundancy +- **Network Latency:** Place master and replicas in the same network or region for optimal performance + +## Troubleshooting + +If replication is not working: + +1. Verify network connectivity between containers +2. Check that the master is accessible from the replica +3. Review logs for errors: `docker logs falkordb-replica1` + +## Next Steps -With replication configured, FalkorDB is now set up for high availability and data redundancy, ensuring that your data is synchronized across multiple instances. This setup provides a robust and fault-tolerant environment for your applications. +With replication configured, FalkorDB provides high availability and data redundancy. Your data is now synchronized across multiple instances, creating a robust and fault-tolerant environment. -If you're interested in learning more about clustering and scaling out, be sure to check out the [Cluster](/operations/cluster) chapter in the documentation. +For horizontal scalability and distributed graph operations, explore [Clustering](/operations/cluster). From 6f2c2bba102e8d976aa54ba6dc9af68ed33ff350 Mon Sep 17 00:00:00 2001 From: Shahar Biron <38566538+shahar-biron@users.noreply.github.com> Date: Sun, 16 Nov 2025 20:20:30 +0200 Subject: [PATCH 014/107] Add documentation for missing procedures (fixes #268) (#269) * Add documentation for missing procedures (fixes #268) - Add comprehensive documentation for algo.MSF (Minimum Spanning Forest) - Add db.idx.fulltext.queryRelationships to procedures table - Add db.idx.vector.queryNodes to procedures table with reference to vector indexing docs - Add db.idx.vector.queryRelationships to procedures table with reference to vector indexing docs - Update algorithms index to include MSF All four procedures mentioned in issue #268 are now documented: - algo.MSF: New dedicated page with examples and use cases - db.idx.fulltext.queryRelationships: Added to procedures table (already documented in indexing.md) - db.idx.vector.queryNodes: Added to procedures table (already documented in indexing.md) - db.idx.vector.queryRelationships: Added to procedures table (already documented in indexing.md) * Fix PR issues: markdown, link fragments, and spelling - Fix invalid link fragment in procedures.md (removed broken #BFS anchor) - Add language specification to code block in msf.md (line 92) - Replace 'very large graphs' with specific metric '100K+ nodes' - Add missing technical terms to wordlist: MST, Kruskal, Prim * Remove accidentally committed files and fix spelling - Remove FalkorDB_Product_Overview.md and PR_SUMMARY_268.md - Add MSTs, Kruskal's, and Prim's to wordlist * Add MSF to wordlist * Fix alphabetical order in wordlist per CodeRabbit review * Apply suggestion from @coderabbitai[bot] Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Guy Korland Co-authored-by: Avi Avni Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .wordlist.txt | 9 ++- algorithms/index.md | 3 + algorithms/msf.md | 177 +++++++++++++++++++++++++++++++++++++++++++ cypher/procedures.md | 6 +- 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 algorithms/msf.md diff --git a/.wordlist.txt b/.wordlist.txt index 052b7c07..2785e126 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -395,10 +395,15 @@ propvalue ro GenAI -WCC -WSL +Kruskal's +MSF +MST +MSTs +Prim's SPpath SSpath +WCC +WSL undirected preprocessing diff --git a/algorithms/index.md b/algorithms/index.md index 14188c37..8d00790a 100644 --- a/algorithms/index.md +++ b/algorithms/index.md @@ -34,6 +34,9 @@ This overview summarizes the available algorithms and links to their individual - **[SSpath](./sspath.md)** Enumerates all paths from a single source node to other nodes, based on constraints like edge filters and depth. +- **[MSF](./msf.md)** + Computes the Minimum Spanning Forest of a graph, finding the minimum spanning tree for each connected component. + For path expressions like `shortestPath()` used directly in Cypher queries, refer to the [Cypher Path Functions section](../cypher/functions.md#path-functions). ## Centrality Measures diff --git a/algorithms/msf.md b/algorithms/msf.md new file mode 100644 index 00000000..ea5b6783 --- /dev/null +++ b/algorithms/msf.md @@ -0,0 +1,177 @@ +--- +title: "MSF" +description: "Minimum Spanning Forest Algorithm" +parent: "Algorithms" +nav_order: 9 +--- + +# Minimum Spanning Forest (MSF) + +The Minimum Spanning Forest algorithm computes the minimum spanning forest of a graph. A minimum spanning forest is a collection of minimum spanning trees, one for each connected component in the graph. + +## What is a Minimum Spanning Forest? + +- For a **connected graph**, the MSF is a single minimum spanning tree (MST) that connects all nodes with the minimum total edge weight +- For a **disconnected graph**, the MSF consists of multiple MSTs, one for each connected component +- The forest contains no cycles and has exactly `N - C` edges, where `N` is the number of nodes and `C` is the number of connected components + +## Use Cases + +- **Network Design**: Minimize cable/pipeline costs when connecting multiple locations +- **Clustering**: Identify natural groupings in data by analyzing the forest structure +- **Image Segmentation**: Group similar pixels using edge weights as similarity measures +- **Road Networks**: Optimize road construction to connect all cities with minimum cost + +## Syntax + +```cypher +CALL algo.MSF( + config: MAP +) YIELD src, dest, weight, relationshipType +``` + +### Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `config` | MAP | Configuration map containing algorithm parameters | + +#### Configuration Options + +| Option | Type | Required | Default | Description | +|--------|------|----------|---------|-------------| +| `sourceNodes` | List of Nodes | No | All nodes | Starting nodes for the algorithm. If not provided, all nodes in the graph are considered | +| `relationshipTypes` | List of Strings | No | All types | Relationship types to traverse. If not provided, all relationship types are considered | +| `relationshipWeightProperty` | String | No | `null` | Property name containing edge weights. If not specified, all edges have weight 1.0 | +| `defaultValue` | Float | No | `1.0` | Default weight for edges that don't have the weight property | + +### Returns + +| Field | Type | Description | +|-------|------|-------------| +| `src` | Node | Source node of the edge in the spanning forest | +| `dest` | Node | Destination node of the edge in the spanning forest | +| `weight` | Float | Weight of the edge | +| `relationshipType` | String | Type of the relationship | + +## Examples + +### Example 1: Basic MSF with Unweighted Graph + +Find the minimum spanning forest treating all edges equally: + +```cypher +CALL algo.MSF({}) YIELD src, dest, weight, relationshipType +RETURN src.name AS source, dest.name AS destination, weight, relationshipType +``` + +### Example 2: MSF with Weighted Edges + +Consider a graph representing cities connected by roads with distances: + +```cypher +// Create a weighted graph +CREATE (a:City {name: 'A'}), (b:City {name: 'B'}), (c:City {name: 'C'}), + (d:City {name: 'D'}), (e:City {name: 'E'}) +CREATE (a)-[:ROAD {distance: 2}]->(b), + (a)-[:ROAD {distance: 3}]->(c), + (b)-[:ROAD {distance: 1}]->(c), + (b)-[:ROAD {distance: 4}]->(d), + (c)-[:ROAD {distance: 5}]->(d), + (d)-[:ROAD {distance: 6}]->(e) + +// Find minimum spanning forest using distance weights +CALL algo.MSF({ + relationshipWeightProperty: 'distance' +}) YIELD src, dest, weight +RETURN src.name AS from, dest.name AS to, weight AS distance +ORDER BY weight +``` + +**Result:** +```text +from | to | distance +-----|----|--------- +B | C | 1.0 +A | B | 2.0 +A | C | 3.0 +B | D | 4.0 +D | E | 6.0 +``` + +### Example 3: MSF on Specific Relationship Types + +Find the spanning forest considering only specific relationship types: + +```cypher +CALL algo.MSF({ + relationshipTypes: ['ROAD', 'HIGHWAY'], + relationshipWeightProperty: 'distance' +}) YIELD src, dest, weight, relationshipType +RETURN src.name AS from, dest.name AS to, weight, relationshipType +``` + +### Example 4: MSF Starting from Specific Nodes + +Compute the spanning forest starting from a subset of nodes: + +```cypher +MATCH (start:City) WHERE start.name IN ['A', 'B'] +WITH collect(start) AS startNodes +CALL algo.MSF({ + sourceNodes: startNodes, + relationshipWeightProperty: 'distance' +}) YIELD src, dest, weight +RETURN src.name AS from, dest.name AS to, weight +``` + +### Example 5: Disconnected Graph + +For a graph with multiple components, MSF returns multiple trees: + +```cypher +// Create two disconnected components +CREATE (a:Node {name: 'A'})-[:CONNECTED {weight: 1}]->(b:Node {name: 'B'}), + (b)-[:CONNECTED {weight: 2}]->(c:Node {name: 'C'}), + (x:Node {name: 'X'})-[:CONNECTED {weight: 3}]->(y:Node {name: 'Y'}) + +// Find MSF +CALL algo.MSF({ + relationshipWeightProperty: 'weight' +}) YIELD src, dest, weight +RETURN src.name AS from, dest.name AS to, weight +``` + +**Result:** Two separate trees (A-B-C and X-Y) + +## Algorithm Details + +FalkorDB's MSF implementation uses an efficient matrix-based approach optimized for graph databases: + +1. **Connected Components**: First identifies all connected components in the graph +2. **MST per Component**: Computes a minimum spanning tree for each component using a variant of Kruskal's or Prim's algorithm +3. **Edge Selection**: Selects edges in order of increasing weight, avoiding cycles + +### Performance Characteristics + +- **Time Complexity**: O(E log V) where E is the number of edges and V is the number of vertices +- **Space Complexity**: O(V + E) +- **Optimized**: Uses sparse matrix representation for efficient computation + +## Best Practices + +1. **Weight Properties**: Ensure weight properties are numeric (integers or floats) +2. **Missing Weights**: Use `defaultValue` to handle edges without weight properties +3. **Large Graphs**: For large graphs (100K+ nodes), consider filtering by `sourceNodes` or `relationshipTypes` +4. **Directed vs Undirected**: The algorithm treats relationships as undirected for spanning forest purposes + +## Related Algorithms + +- **[WCC (Weakly Connected Components)](./wcc.md)**: Identify connected components before running MSF +- **[BFS](./bfs.md)**: Traverse the resulting spanning forest +- **[SPpath](./sppath.md)**: Find shortest paths using the spanning forest structure + +## See Also + +- [Cypher Procedures](../cypher/procedures.md) +- [Graph Algorithms Overview](./index.md) diff --git a/cypher/procedures.md b/cypher/procedures.md index 5f501c50..12d15350 100644 --- a/cypher/procedures.md +++ b/cypher/procedures.md @@ -39,6 +39,10 @@ GRAPH.QUERY social "CALL db.labels() YIELD label" | db.idx.fulltext.createNodeIndex | `label`, `property` [, `property` ...] | none | Builds a full-text searchable index on a label and the 1 or more specified properties. | | db.idx.fulltext.drop | `label` | none | Deletes the full-text index associated with the given label. | | db.idx.fulltext.queryNodes | `label`, `string` | `node`, `score` | Retrieve all nodes that contain the specified string in the full-text indexes on the given label. | +| db.idx.fulltext.queryRelationships | `relationshipType`, `string` | `relationship`, `score` | Retrieve all relationships that contain the specified string in the full-text indexes on the given relationship type. See [Full-Text Indexing](/cypher/indexing#full-text-indexing) for details. | +| db.idx.vector.queryNodes | `label`, `attribute`, `k`, `query` | `node`, `score` | Retrieve up to k nodes with vectors most similar to the query vector using the specified label and attribute. See [Vector Indexing](/cypher/indexing#vector-indexing) for details. | +| db.idx.vector.queryRelationships | `relationshipType`, `attribute`, `k`, `query` | `relationship`, `score` | Retrieve up to k relationships with vectors most similar to the query vector using the specified relationship type and attribute. See [Vector Indexing](/cypher/indexing#vector-indexing) for details. | | algo.pageRank | `label`, `relationship-type` | `node`, `score` | Runs the pagerank algorithm over nodes of given label, considering only edges of given relationship type. | -| [algo.BFS](#BFS) | `source-node`, `max-level`, `relationship-type` | `nodes`, `edges` | Performs BFS to find all nodes connected to the source. A `max level` of 0 indicates unlimited and a non-NULL `relationship-type` defines the relationship type that may be traversed. | +| algo.BFS | `source-node`, `max-level`, `relationship-type` | `nodes`, `edges` | Performs BFS to find all nodes connected to the source. A `max level` of 0 indicates unlimited and a non-NULL `relationship-type` defines the relationship type that may be traversed. See [BFS Algorithm](/algorithms/bfs) for details. | +| algo.MSF | `config` | `src`, `dest`, `weight`, `relationshipType` | Computes the Minimum Spanning Forest of the graph. See [MSF Algorithm](/algorithms/msf) for details. | | dbms.procedures() | none | `name`, `mode` | List all procedures in the DBMS, yields for every procedure its name and mode (read/write). | From 8af156b7bb5888abc88b8d75987c5d367a5d07f2 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:39:11 +0200 Subject: [PATCH 015/107] Create get_started.md for FalkorDB Cloud DBaaS Added a comprehensive guide for getting started with FalkorDB's Cloud DBaaS, detailing features, tiers, and deployment options. --- cloud/get_started.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 cloud/get_started.md diff --git a/cloud/get_started.md b/cloud/get_started.md new file mode 100644 index 00000000..c953fe74 --- /dev/null +++ b/cloud/get_started.md @@ -0,0 +1,32 @@ +# FalkorDB Cloud DBaaS +Get started with FalkorDB's Cloud Offering. Several enterprise features, like multi-tenancy, are available across all tiers. Browse our plans and get started with the one that best-suits your needs, then scale & upgrade with ease when you're ready. + +## Features & Services +- Multi-Graph / Multi-Tenancy +- Graph Access Control +- TLS +- Automated Backups +- VPC Peering +- Dedicated Cluster Deployment +- High Availability +- Multi-zone Deployment +- Scalability +- Continuous Persistence +- Dedicated Support +- Advanced Monitoring +- Dedicated Account Manager +- ☁️ Cloud Providers: AWS, GCP +> *Azure: Bring-Your-Own-Cloud + +## Free Tier +The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. + +## Startup Tier +The FalkorDB Startup Tier provides you with a production-ready Standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start getting insights! + +## Pro Tier +The FalkorDB Pro Tier provides you with a production-ready FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start getting insights! + +## Enterprise +Contact us + From d26effb7348a37d50e7a24f5494f72fe7a6b59ca Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:44:46 +0200 Subject: [PATCH 016/107] Update get_started.md --- cloud/get_started.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cloud/get_started.md b/cloud/get_started.md index c953fe74..e8ac3992 100644 --- a/cloud/get_started.md +++ b/cloud/get_started.md @@ -1,7 +1,9 @@ -# FalkorDB Cloud DBaaS -Get started with FalkorDB's Cloud Offering. Several enterprise features, like multi-tenancy, are available across all tiers. Browse our plans and get started with the one that best-suits your needs, then scale & upgrade with ease when you're ready. +# FalkorDB Cloud DBaaS + +Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready. ## Features & Services + - Multi-Graph / Multi-Tenancy - Graph Access Control - TLS @@ -16,17 +18,21 @@ Get started with FalkorDB's Cloud Offering. Several enterprise features, like mu - Advanced Monitoring - Dedicated Account Manager - ☁️ Cloud Providers: AWS, GCP + > *Azure: Bring-Your-Own-Cloud ## Free Tier + The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. ## Startup Tier -The FalkorDB Startup Tier provides you with a production-ready Standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start getting insights! + +The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. ## Pro Tier -The FalkorDB Pro Tier provides you with a production-ready FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start getting insights! + +The FalkorDB Pro Tier provides a production-ready FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. ## Enterprise -Contact us +Contact us From 60e69c28bea5f4c33cc1bae02413370dc197c0ba Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:46:26 +0200 Subject: [PATCH 017/107] Rename get_started.md to index.md --- cloud/{get_started.md => index.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cloud/{get_started.md => index.md} (100%) diff --git a/cloud/get_started.md b/cloud/index.md similarity index 100% rename from cloud/get_started.md rename to cloud/index.md From aecc772bfba919a6539f18a49d47f132d6da7e35 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:49:00 +0200 Subject: [PATCH 018/107] Create free-tier.md for Free Tier documentation Add documentation for FalkorDB DBaaS Free Tier --- cloud/free-tier.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 cloud/free-tier.md diff --git a/cloud/free-tier.md b/cloud/free-tier.md new file mode 100644 index 00000000..b03fe913 --- /dev/null +++ b/cloud/free-tier.md @@ -0,0 +1,9 @@ +--- +title: "Free Tier" +parent: "Cloud" +nav_order: 1 +description: "FalkorDB DBaaS Free Tier" +--- + +# Free Tier +## FalkorDB DBaaS From 83c72deaf5227cf5e21fae9c2d68cd26a279c230 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:50:45 +0200 Subject: [PATCH 019/107] Add metadata to cloud/index.md Added front matter for Cloud DBaaS documentation. --- cloud/index.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cloud/index.md b/cloud/index.md index e8ac3992..73a6fe01 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -1,3 +1,10 @@ +--- +title: "Cloud DBaaS" +description: Cloud Offering +nav_order: +has_children: true +--- + # FalkorDB Cloud DBaaS Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready. From 3ee85e52c9729bfa23608a9791a48379b3d5461b Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:23:05 +0200 Subject: [PATCH 020/107] Update free-tier.md --- cloud/free-tier.md | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/cloud/free-tier.md b/cloud/free-tier.md index b03fe913..b637cab4 100644 --- a/cloud/free-tier.md +++ b/cloud/free-tier.md @@ -1,9 +1,43 @@ --- title: "Free Tier" -parent: "Cloud" +parent: "Cloud DBaaS" nav_order: 1 description: "FalkorDB DBaaS Free Tier" --- +![FalkorDB Cloud Free Tier Banner](https://github.com/user-attachments/assets/062cb5c5-d969-4481-ab1b-1802fea0732a) + # Free Tier -## FalkorDB DBaaS +FalkorDB's free cloud tier gives you instant access to a graph database with multi-graph support and multi-tenancy capabilities. You can deploy on AWS or GCP with 100MB of storage and rely on community support to get started. + +The free tier provides everything you need to explore FalkorDB and build initial prototypes. When your application grows and requires TLS security, VPC networking, high availability, automated backups, or dedicated support, you can upgrade to a paid plan that includes these enterprise features. + + + +| Feature | Included | +|---------|----------| +| Multi-Graph / Multi-Tenancy | ✓ | +| Community Support | ✓ | +| Cloud Providers (AWS, GCP) | ✓ | +| Storage (100MB) | ✓ | +| TLS | ✗ | +| VPC | ✗ | +| Cluster Deployment | ✗ | +| High Availability | ✗ | +| Multi-zone Deployment | ✗ | +| Scalability | ✗ | +| Continuous Persistence | ✗ | +| Automated Backups | ✗ | +| Advanced Monitoring | ✗ | +| Dedicated Account Manager | ✗ | + +#### Terms +> ⚠️ Free instances that aren't utilized for 1 day will be stopped, and deleted after 7 days. +Need an extension? Speak to [sales](https://www.falkordb.com/get-a-demo/)) + +## Getting Started +### Video Guide +FalkorDB Graph DBaaS Free Tier Tutorial Video + +> ▶️ Watch: https://www.youtube.com/watch?v=z0XO4pb2t5Y
+> ⚙️ Spin up your first FalkorDB Cloud instance: [Sign up](https://app.falkordb.cloud/signup) From f8789ca870df4f834dc7fea8121051ed0dff20f9 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:23:59 +0200 Subject: [PATCH 021/107] Create features documentation for FalkorDB DBaaS Added detailed features documentation for FalkorDB DBaaS, covering multi-tenancy, cloud provider integrations, storage, TLS, VPC, persistence, and solution architecture. --- cloud/features.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 cloud/features.md diff --git a/cloud/features.md b/cloud/features.md new file mode 100644 index 00000000..c4c3638d --- /dev/null +++ b/cloud/features.md @@ -0,0 +1,80 @@ +--- +title: "Features" +parent: "Cloud DBaaS" +nav_order: 4 +description: "FalkorDB DBaaS Features" +--- + +# Features + +## Multi-Tenancy +Multi-tenancy lets you run multiple isolated graph databases within a single FalkorDB instance. Each tenant operates independently with its own data, queries, and access controls while sharing the underlying infrastructure. + +Developers building SaaS applications need multi-tenancy to serve multiple customers without deploying separate database instances for each one. This approach reduces operational overhead and infrastructure costs while maintaining strict data isolation between tenants. + +In practice, you create distinct graph databases for each customer or project, and FalkorDB handles the isolation automatically. Your application connects to the appropriate tenant database using different credentials or connection strings. + +## Cloud Providers +### AWS +FalkorDB runs on Amazon Web Services infrastructure, giving you access to AWS's global network of data centers and integration with other AWS services. You can deploy FalkorDB instances in several AWS regions and connect them to your existing AWS resources. + +Teams already using AWS benefit from keeping their graph database in the same cloud environment as their applications. This setup reduces latency and simplifies network configuration since your services communicate within the AWS network. + +When you deploy on AWS, you choose your preferred region, and FalkorDB provisions the necessary compute and storage resources in that location. + +### Google Cloud Platform (GCP) +FalkorDB integrates with Google Cloud Platform, allowing you to run graph databases on Google's infrastructure. You gain access to GCP's global network and can combine FalkorDB with other Google Cloud services. + +Organizations using GCP for their applications should deploy FalkorDB in the same cloud to maintain consistent infrastructure management. Keeping your database and applications on GCP reduces cross-cloud data transfer costs and latency. + +You select a GCP region during deployment, and FalkorDB sets up your graph database instance within Google's infrastructure. + +> Note: Microsoft Azure is currently available in a Bring-Your-Own-Cloud configuration + +## Storage +Storage defines how much disk space your graph database has for nodes, relationships, properties, and indexes. The amount of storage you need depends on your graph size and how much data you store in each node and relationship. + +Applications with large knowledge graphs, social networks, or recommendation systems require substantial storage. Running out of storage stops your database from accepting new data, so you must monitor usage and scale accordingly. + +FalkorDB allocates the specified storage capacity to your instance. You can track how much space your graph consumes and increase storage limits as your data grows. + +## TLS +TLS (Transport Layer Security) encrypts all data transmitted between your application and FalkorDB. This encryption prevents anyone intercepting network traffic from reading your queries or results. + +Applications handling sensitive data must use TLS to protect information in transit. Without encryption, credentials, personal data, and business logic become vulnerable when traveling across networks. + +When you enable TLS, FalkorDB requires encrypted connections. Your application must configure its database client to use TLS, and all communication happens over secure channels. + +## VPC +A Virtual Private Cloud (VPC) creates an isolated network environment where your FalkorDB instance runs separately from the public internet. Only resources within your VPC or those you explicitly authorize can reach your database. + +Organizations with security requirements need VPC deployment to control network access to their databases. VPCs prevent unauthorized connection attempts and give you granular control over which services can communicate with FalkorDB. + +You deploy FalkorDB into your existing VPC, and the database becomes accessible only through your private network. Your applications connect using private IP addresses instead of public endpoints. + +## Clusters + +## Availability + +## Deployment Options + +## Scalability + +## Persistence +Persistence ensures your graph data survives system restarts, crashes, or failures by writing changes to disk. Without persistence, you lose all data when the database stops. + +Any application storing important data requires persistence to maintain durability. In-memory-only databases lose everything during unexpected shutdowns, making them unsuitable for production workloads. + +FalkorDB persists data through regular snapshots and transaction logs. These mechanisms guarantee that committed transactions remain safe even if the system crashes immediately afterward. + +## Backups + +## Monitoring & Analytics + +### Additional Features & Services +#### Solution Architecture +Solution architecture support helps you design how FalkorDB integrates with your broader application infrastructure. This guidance covers connection patterns, data modeling approaches, and best practices for specific use cases. + +Teams building complex systems benefit from architectural advice to avoid common pitfalls and optimize their graph database implementation. Poor architectural decisions early in development create technical debt that becomes expensive to fix later. + +Architecture consultations provide recommendations on graph schema design, query optimization strategies, and integration patterns that match your application requirements. From 1d9c16e3923d75179fef2d99b026dbe2fa9f2cf5 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:26:39 +0200 Subject: [PATCH 022/107] Update Multi-Graph feature link in free-tier.md --- cloud/free-tier.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/free-tier.md b/cloud/free-tier.md index b637cab4..9f09afde 100644 --- a/cloud/free-tier.md +++ b/cloud/free-tier.md @@ -16,7 +16,7 @@ The free tier provides everything you need to explore FalkorDB and build initial | Feature | Included | |---------|----------| -| Multi-Graph / Multi-Tenancy | ✓ | +| [Multi-Graph / Multi-Tenancy](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/features.md#multi-tenancy) | ✓ | | Community Support | ✓ | | Cloud Providers (AWS, GCP) | ✓ | | Storage (100MB) | ✓ | From 483d5a53306be3e838071b13d5b31bebe0c013f3 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:32:50 +0200 Subject: [PATCH 023/107] update docs --- .wordlist.txt | 1 - integration/rest.md | 94 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 22 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index c891fd38..163c39c0 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -257,7 +257,6 @@ relTypes relationshipTypes relationshipId reltype -reltype reltypeList replaceRegEx rgraph diff --git a/integration/rest.md b/integration/rest.md index 543006f6..994b9bf4 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -36,11 +36,8 @@ curl -X POST "http://your-falkordb-browser-url/api/auth/login" \ This will return a JWT token that you'll use for all subsequent requests: ```json { - "token": "", - "user": { - "username": "default", - "role": "Admin" - } + "message": "Authentication successful", + "token": "" } ``` @@ -137,50 +134,94 @@ curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH% ## Authentication All endpoints except `/api/auth/login` require authentication using a JWT bearer token in the Authorization header: -``` +```http Authorization: Bearer ``` ### **User login** - `POST /api/auth/login` -Authenticate user with username and password. +Generate JWT Token (Login) - Authenticate user and generate a JWT Personal Access Token (PAT) for external API access. #### Request Body - Content-Type: `application/json` - Required fields: `username`, `password` +- Optional fields: `name`, `expiresAt`, `ttlSeconds`, `host`, `port`, `tls`, `ca` Example request: ```json { "username": "default", - "password": "" + "password": "", + "name": "API Token", + "expiresAt": null, + "ttlSeconds": 31622400, + "host": "localhost", + "port": "6379", + "tls": "false", + "ca": "" } ``` +**Request Parameters:** +- `username` (required): Username for database connection +- `password` (required): Password for database connection (leave empty for 'default' user) +- `name` (optional): Token name +- `expiresAt` (optional): Token expiration date in ISO 8601 format +- `ttlSeconds` (optional): Time-to-live in seconds (default: 31622400) +- `host` (optional): FalkorDB host (default: "localhost") +- `port` (optional): FalkorDB port (default: "6379") +- `tls` (optional): Enable TLS connection - "true" or "false" +- `ca` (optional): Base64-encoded CA certificate for TLS + #### Responses -- **200**: Login successful +- **200**: Token generated successfully - Content-Type: `application/json` - Example response: ```json { - "token": "", - "user": { - "username": "default", - "role": "Admin" - } + "message": "Authentication successful", + "token": "" } ``` -- **400**: Bad request - missing username or password -- **401**: Invalid credentials -- **500**: Internal server error +- **400**: Bad request - Invalid JSON, expiration date in the past, or invalid TTL value + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Expiration date must be in the future" + } + ``` + +- **401**: Authentication failed - Invalid credentials or connection failed + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Invalid credentials or connection failed" + } + ``` + +- **500**: Server configuration error - Missing NEXTAUTH_SECRET + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Server configuration error: NEXTAUTH_SECRET is not set" + } + ``` ### **Revoke JWT token** - `POST /api/auth/revoke` -Revoke a JWT token by removing it from the active tokens list in Redis. Once revoked, the token cannot be used for authentication. Admins can revoke any token, while regular users can only revoke their own tokens. +Revoke a JWT token by marking it as inactive in FalkorDB. Once revoked, the token cannot be used for authentication. Admins can revoke any token, while regular users can only revoke their own tokens. + +**Note:** Provide either `token` or `token_id` (not both) #### Headers - `Authorization: Bearer ` (required) @@ -188,15 +229,26 @@ Revoke a JWT token by removing it from the active tokens list in Redis. Once rev #### Request Body - Content-Type: `application/json` -- Required field: `token` +- Required field: Either `token` or `token_id` (not both) -Example request: +Example request (using token): ```json { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + "token": "" } ``` +Example request (using token_id): +```json +{ + "token_id": "1761055513181-215c579b-c6e1-4f10-9b07-aacbf89cda21" +} +``` + +**Request Parameters:** +- `token` (optional): JWT token to revoke +- `token_id` (optional): Token ID to revoke + #### Responses - **200**: Token revoked successfully From 77c88dadcc5d28376e57a1c1a2e2d9a34fc5e06d Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 18 Nov 2025 10:36:32 +0200 Subject: [PATCH 024/107] fix spell check --- .wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.wordlist.txt b/.wordlist.txt index 163c39c0..2af772ff 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -77,6 +77,7 @@ MotoGP NRedisGraph NaN NFalkorDB +NEXTAUTH NodeJS Nostem NumItems From d9f4dbf8f0b175f84e40904c5f78179dd00bebbe Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 20:00:43 +0200 Subject: [PATCH 025/107] Break indexing documentation into subfolder with dedicated pages per index type (#286) * Break indexing page into folder structure with sub-pages per index type --- .wordlist.txt | 24 + cypher/index.md | 2 +- cypher/indexing.md | 863 ------------------------------ cypher/indexing/fulltext-index.md | 636 ++++++++++++++++++++++ cypher/indexing/index.md | 34 ++ cypher/indexing/range-index.md | 488 +++++++++++++++++ cypher/indexing/vector-index.md | 421 +++++++++++++++ cypher/procedures.md | 6 +- index.md | 2 +- 9 files changed, 1608 insertions(+), 868 deletions(-) delete mode 100644 cypher/indexing.md create mode 100644 cypher/indexing/fulltext-index.md create mode 100644 cypher/indexing/index.md create mode 100644 cypher/indexing/range-index.md create mode 100644 cypher/indexing/vector-index.md diff --git a/.wordlist.txt b/.wordlist.txt index 2785e126..7318dd06 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -667,3 +667,27 @@ NodePort orphaned replicas SQL's +Levenshtein +autocomplete +tokenization +tokenized +HNSW +ANN +tradeoff +tradeoffs +unnormalized +Forst +configurability +Metaphone +ProcedureCall + +dimensionality +efConstruction +efRuntime +queryVector +DESC +tolist +pc +queryEmbedding +printf +Jngle diff --git a/cypher/index.md b/cypher/index.md index 2d24d32e..b4a70e40 100644 --- a/cypher/index.md +++ b/cypher/index.md @@ -42,4 +42,4 @@ See the list of available graph [algorithms](/algorithms). ## Indexing -See how to use [indexing](/cypher/indexing). +See how to use [indexing](/cypher/indexing/). diff --git a/cypher/indexing.md b/cypher/indexing.md deleted file mode 100644 index 78342e63..00000000 --- a/cypher/indexing.md +++ /dev/null @@ -1,863 +0,0 @@ ---- -title: "Indexing" -nav_order: 21 -description: > - FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed. -parent: "Cypher Language" ---- - -# Indexing - -## Range Index - -FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed. - -### Creating an index for a node label - -For a node label, the index creation syntax is: - -{% capture shell_0 %} -GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)" -{% endcapture %} - -{% capture python_0 %} -graph.query("CREATE INDEX FOR (p:Person) ON (p.age)") -{% endcapture %} - -{% capture javascript_0 %} -await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); -{% endcapture %} - -{% capture java_0 %} -graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); -{% endcapture %} - -{% capture rust_0 %} -graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="create_index_tabs" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %} - -An old syntax is also supported: - -{% capture shell_1 %} -GRAPH.QUERY DEMO_GRAPH "CREATE INDEX ON :Person(age)" -{% endcapture %} - -{% capture python_1 %} -graph.query("CREATE INDEX ON :Person(age)") -{% endcapture %} - -{% capture javascript_1 %} -await graph.query("CREATE INDEX ON :Person(age)"); -{% endcapture %} - -{% capture java_1 %} -graph.query("CREATE INDEX ON :Person(age)"); -{% endcapture %} - -{% capture rust_1 %} -graph.query("CREATE INDEX ON :Person(age)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="old_syntax_tabs" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %} - -After an index is explicitly created, it will automatically be used by queries that reference that label and any indexed property in a filter. - -{% capture shell_2 %} -GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 80 RETURN p" -1) "Results" -2) " Project" -3) " Index Scan | (p:Person)" -{% endcapture %} - -{% capture python_2 %} -result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p") -print(result) -# Output: -# Results -# Project -# Index Scan | (p:Person) -{% endcapture %} - -{% capture javascript_2 %} -const result = await graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p"); -console.log(result); -// Output: -// Results -// Project -// Index Scan | (p:Person) -{% endcapture %} - -{% capture java_2 %} -String result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p"); -System.out.println(result); -// Output: -// Results -// Project -// Index Scan | (p:Person) -{% endcapture %} - -{% capture rust_2 %} -let result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p").execute().await?; -println!("{}", result); -// Output: -// Results -// Project -// Index Scan | (p:Person) -{% endcapture %} - -{% include code_tabs.html id="explain_tabs" shell=shell_2 python=python_2 javascript=javascript_2 java=java_2 rust=rust_2 %} - -This can significantly improve the runtime of queries with very specific filters. An index on `:employer(name)`, for example, will dramatically benefit the query: - -{% capture shell_3 %} -GRAPH.QUERY DEMO_GRAPH -"MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p" -{% endcapture %} - -{% capture python_3 %} -result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p") -{% endcapture %} - -{% capture javascript_3 %} -const result = await graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"); -{% endcapture %} - -{% capture java_3 %} -ResultSet result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"); -{% endcapture %} - -{% capture rust_3 %} -let result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="employer_query_tabs" shell=shell_3 python=python_3 javascript=javascript_3 java=java_3 rust=rust_3 %} - -An example of utilizing a geospatial index to find `Employer` nodes within 5 kilometers of Scranton are: - -{% capture shell_4 %} -GRAPH.QUERY DEMO_GRAPH -"WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e" -{% endcapture %} - -{% capture python_4 %} -result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e") -{% endcapture %} - -{% capture javascript_4 %} -const result = await graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"); -{% endcapture %} - -{% capture java_4 %} -ResultSet result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"); -{% endcapture %} - -{% capture rust_4 %} -let result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="geospatial_tabs" shell=shell_4 python=python_4 javascript=javascript_4 java=java_4 rust=rust_4 %} - -Geospatial indexes can currently only be leveraged with `<` and `<=` filters; matching nodes outside of the given radius is performed using conventional matching. - -### Creating an index for a relationship type - -For a relationship type, the index creation syntax is: - -{% capture shell_5 %} -GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)" -{% endcapture %} - -{% capture python_5 %} -graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)") -{% endcapture %} - -{% capture javascript_5 %} -await graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"); -{% endcapture %} - -{% capture java_5 %} -graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"); -{% endcapture %} - -{% capture rust_5 %} -graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="relationship_index_tabs" shell=shell_5 python=python_5 javascript=javascript_5 java=java_5 rust=rust_5 %} - -Then the execution plan for using the index: - -{% capture shell_6 %} -GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp" -1) "Results" -2) " Project" -3) " Edge By Index Scan | [f:FOLLOW]" -4) " Node By Index Scan | (p:Person)" -{% endcapture %} - -{% capture python_6 %} -result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp") -print(result) -# Output: -# Results -# Project -# Edge By Index Scan | [f:FOLLOW] -# Node By Index Scan | (p:Person) -{% endcapture %} - -{% capture javascript_6 %} -const result = await graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"); -console.log(result); -// Output: -// Results -// Project -// Edge By Index Scan | [f:FOLLOW] -// Node By Index Scan | (p:Person) -{% endcapture %} - -{% capture java_6 %} -String result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"); -System.out.println(result); -// Output: -// Results -// Project -// Edge By Index Scan | [f:FOLLOW] -// Node By Index Scan | (p:Person) -{% endcapture %} - -{% capture rust_6 %} -let result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp").execute().await?; -println!("{}", result); -// Output: -// Results -// Project -// Edge By Index Scan | [f:FOLLOW] -// Node By Index Scan | (p:Person) -{% endcapture %} - -{% include code_tabs.html id="relationship_explain_tabs" shell=shell_6 python=python_6 javascript=javascript_6 java=java_6 rust=rust_6 %} - -This can significantly improve the runtime of queries that traverse super nodes or when we want to start traverse from relationships. - -### Deleting an index for a node label - -For a node label, the index deletion syntax is: - -{% capture shell_7 %} -GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :Person(age)" -{% endcapture %} - -{% capture python_7 %} -graph.query("DROP INDEX ON :Person(age)") -{% endcapture %} - -{% capture javascript_7 %} -await graph.query("DROP INDEX ON :Person(age)"); -{% endcapture %} - -{% capture java_7 %} -graph.query("DROP INDEX ON :Person(age)"); -{% endcapture %} - -{% capture rust_7 %} -graph.query("DROP INDEX ON :Person(age)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="drop_node_index_tabs" shell=shell_7 python=python_7 javascript=javascript_7 java=java_7 rust=rust_7 %} - -### Deleting an index for a relationship type - -For a relationship type, the index deletion syntax is: - -{% capture shell_8 %} -GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :FOLLOW(created_at)" -{% endcapture %} - -{% capture python_8 %} -graph.query("DROP INDEX ON :FOLLOW(created_at)") -{% endcapture %} - -{% capture javascript_8 %} -await graph.query("DROP INDEX ON :FOLLOW(created_at)"); -{% endcapture %} - -{% capture java_8 %} -graph.query("DROP INDEX ON :FOLLOW(created_at)"); -{% endcapture %} - -{% capture rust_8 %} -graph.query("DROP INDEX ON :FOLLOW(created_at)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="drop_relationship_index_tabs" shell=shell_8 python=python_8 javascript=javascript_8 java=java_8 rust=rust_8 %} - -### Array Indices - -FalkorDB supports indexing on array properties containing scalar values (e.g., integers, floats, strings), enabling efficient lookups for elements within such arrays. - -Note: Complex types like nested arrays, maps, or vectors are not supported for indexing. - -The following example demonstrates how to index and search an array property: - -{% capture shell_9 %} -# Create a node with an array property -GRAPH.QUERY DEMO_GRAPH "CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})" - -# Create an index on the array property -GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.samples)" - -# Use the index to search for nodes containing a specific value in the array -GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE 90 IN p.samples RETURN p" -{% endcapture %} - -{% capture python_9 %} -# Create a node with an array property -graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})") - -# Create an index on the array property -graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)") - -# Use the index to search for nodes containing a specific value in the array -result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p") -{% endcapture %} - -{% capture javascript_9 %} -// Create a node with an array property -await graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"); - -// Create an index on the array property -await graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)"); - -// Use the index to search for nodes containing a specific value in the array -const result = await graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p"); -{% endcapture %} - -{% capture java_9 %} -// Create a node with an array property -graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"); - -// Create an index on the array property -graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)"); - -// Use the index to search for nodes containing a specific value in the array -ResultSet result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p"); -{% endcapture %} - -{% capture rust_9 %} -// Create a node with an array property -graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})").execute().await?; - -// Create an index on the array property -graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)").execute().await?; - -// Use the index to search for nodes containing a specific value in the array -let result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="array_index_tabs" shell=shell_9 python=python_9 javascript=javascript_9 java=java_9 rust=rust_9 %} - -## Full-text indexing - -FalkorDB leverages the indexing capabilities of [RediSearch](https://redis.io/docs/interact/search-and-query/) to provide full-text indices through procedure calls. - -## Creating a full-text index for a node label - -To construct a full-text index on the `title` property of all nodes with label `Movie`, use the syntax: - -{% capture shell_10 %} -GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', 'title')" -{% endcapture %} - -{% capture python_10 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')") -{% endcapture %} - -{% capture javascript_10 %} -await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"); -{% endcapture %} - -{% capture java_10 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"); -{% endcapture %} - -{% capture rust_10 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_create_tabs" shell=shell_10 python=python_10 javascript=javascript_10 java=java_10 rust=rust_10 %} - -More properties can be added to this index by adding their names to the above set of arguments, or using this syntax again with the additional names. - -{% capture shell_11 %} -GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')" -{% endcapture %} - -{% capture python_11 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')") -{% endcapture %} - -{% capture javascript_11 %} -await graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"); -{% endcapture %} - -{% capture java_11 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"); -{% endcapture %} - -{% capture rust_11 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_multi_property_tabs" shell=shell_11 python=python_11 javascript=javascript_11 java=java_11 rust=rust_11 %} - -RediSearch provide 2 index configuration options: - -1. Language - Define which language to use for stemming text, which is adding the base form of a word to the index. This allows the query for "going" to also return results for "go" and "gone", for example. -2. Stopwords - These are words that are usually so common that they do not add much information to search, but take up a lot of space and CPU time in the index. - -To construct a full-text index on the `title` property using `German` language and using custom stopwords of all nodes with label `Movie`, use the syntax: - -{% capture shell_12 %} -GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')" -{% endcapture %} - -{% capture python_12 %} -graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')") -{% endcapture %} - -{% capture javascript_12 %} -await graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"); -{% endcapture %} - -{% capture java_12 %} -graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"); -{% endcapture %} - -{% capture rust_12 %} -graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_config_tabs" shell=shell_12 python=python_12 javascript=javascript_12 java=java_12 rust=rust_12 %} - -RediSearch provide 3 additional field configuration options: - -1. Weight - The importance of the text in the field -2. Nostem - Skip stemming when indexing text -3. Phonetic - Enable phonetic search on the text - -To construct a full-text index on the `title` property with phonetic search of all nodes with label `Movie`, use the syntax: - -{% capture shell_13 %} -GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})" -{% endcapture %} - -{% capture python_13 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})") -{% endcapture %} - -{% capture javascript_13 %} -await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"); -{% endcapture %} - -{% capture java_13 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"); -{% endcapture %} - -{% capture rust_13 %} -graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_phonetic_tabs" shell=shell_13 python=python_13 javascript=javascript_13 java=java_13 rust=rust_13 %} - -## Utilizing a full-text index for a node label - -An index can be invoked to match any whole words contained within: - -{% capture shell_14 %} -GRAPH.QUERY DEMO_GRAPH -"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title" -1) 1) "node.title" -2) 1) 1) "The Jungle Book" - 2) 1) "The Book of Life" -3) 1) "Query internal execution time: 0.927409 milliseconds" -{% endcapture %} - -{% capture python_14 %} -result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title") -for record in result: - print(record["node.title"]) -# Output: -# The Jungle Book -# The Book of Life -{% endcapture %} - -{% capture javascript_14 %} -const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"); -for (const record of result.data) { - console.log(record["node.title"]); -} -// Output: -// The Jungle Book -// The Book of Life -{% endcapture %} - -{% capture java_14 %} -ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"); -for (Record record : result) { - System.out.println(record.get("node.title")); -} -// Output: -// The Jungle Book -// The Book of Life -{% endcapture %} - -{% capture rust_14 %} -let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title").execute().await?; -for record in result.data() { - println!("{}", record["node.title"]); -} -// Output: -// The Jungle Book -// The Book of Life -{% endcapture %} - -{% include code_tabs.html id="fulltext_query_tabs" shell=shell_14 python=python_14 javascript=javascript_14 java=java_14 rust=rust_14 %} - -This CALL clause can be interleaved with other Cypher clauses to perform more elaborate manipulations: - -```sh -GRAPH.QUERY DEMO_GRAPH -"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node AS m -WHERE m.genre = 'Adventure' -RETURN m ORDER BY m.rating" -1) 1) "m" -2) 1) 1) 1) 1) "id" - 2) (integer) 1168 - 2) 1) "labels" - 2) 1) "Movie" - 3) 1) "properties" - 2) 1) 1) "genre" - 2) "Adventure" - 2) 1) "rating" - 2) "7.6" - 3) 1) "votes" - 2) (integer) 151342 - 4) 1) "year" - 2) (integer) 2016 - 5) 1) "title" - 2) "The Jungle Book" -3) 1) "Query internal execution time: 0.226914 milliseconds" -``` - -In addition to yielding matching nodes, full-text index scans will return the score of each node. This is the [TF-IDF](https://redis.io/docs/interact/search-and-query/advanced-concepts/scoring/#tfidf-default) score of the node, which is informed by how many times the search terms appear in the node and how closely grouped they are. This can be observed in the example: - -```sh -GRAPH.QUERY DEMO_GRAPH -"CALL db.idx.fulltext.queryNodes('Node', 'hello world') YIELD node, score RETURN score, node.val" -1) 1) "score" - 2) "node.val" -2) 1) 1) "2" - 2) "hello world" - 2) 1) "1" - 2) "hello to a different world" -3) 1) "Cached execution: 1" - 2) "Query internal execution time: 0.335401 milliseconds" -``` - -## Deleting a full-text index for a node label - -For a node label, the full-text index deletion syntax is: - -{% capture shell_15 %} -GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.drop('Movie')" -{% endcapture %} - -{% capture python_15 %} -graph.query("CALL db.idx.fulltext.drop('Movie')") -{% endcapture %} - -{% capture javascript_15 %} -await graph.query("CALL db.idx.fulltext.drop('Movie')"); -{% endcapture %} - -{% capture java_15 %} -graph.query("CALL db.idx.fulltext.drop('Movie')"); -{% endcapture %} - -{% capture rust_15 %} -graph.query("CALL db.idx.fulltext.drop('Movie')").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_drop_tabs" shell=shell_15 python=python_15 javascript=javascript_15 java=java_15 rust=rust_15 %} - -## Creating Full-Text indexing for Relation Labels -To create a full-text index on the name property of all relations with the label Manager and enable phonetic search, use the following syntax: - -{% capture shell_16 %} -GRAPH.QUERY DEMO_GRAPH "CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)" -{% endcapture %} - -{% capture python_16 %} -graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)") -{% endcapture %} - -{% capture javascript_16 %} -await graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"); -{% endcapture %} - -{% capture java_16 %} -graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"); -{% endcapture %} - -{% capture rust_16 %} -graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_relation_create_tabs" shell=shell_16 python=python_16 javascript=javascript_16 java=java_16 rust=rust_16 %} -## Querying with a Full-Text Index -To search for specific words within the indexed relations, use: - -{% capture shell_17 %} -GRAPH.QUERY DEMO_GRAPH -"CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name" -{% endcapture %} - -{% capture python_17 %} -result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name") -{% endcapture %} - -{% capture javascript_17 %} -const result = await graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"); -{% endcapture %} - -{% capture java_17 %} -ResultSet result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"); -{% endcapture %} - -{% capture rust_17 %} -let result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_relation_query_tabs" shell=shell_17 python=python_17 javascript=javascript_17 java=java_17 rust=rust_17 %} - -## Deleting a Full-Text Index -To delete the full-text index for a specific relation label, use: - -{% capture shell_18 %} -GRAPH.QUERY DEMO_GRAPH "DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)" -{% endcapture %} - -{% capture python_18 %} -graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)") -{% endcapture %} - -{% capture javascript_18 %} -await graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); -{% endcapture %} - -{% capture java_18 %} -graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); -{% endcapture %} - -{% capture rust_18 %} -graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="fulltext_relation_drop_tabs" shell=shell_18 python=python_18 javascript=javascript_18 java=java_18 rust=rust_18 %} - -## Vector indexing - -With the introduction of the `vector` data-type a new type of index was introduced. -A vector index is a dedicated index for indexing and searching through vectors. - -To create this type of index use the following syntax: - -```cypher -CREATE VECTOR INDEX FOR ON OPTIONS -``` - -The options are: -``` -{ - dimension: INT, // Required, length of the vector to be indexed - similarityFunction: STRING, // Required, currently only euclidean or cosine are allowed - M: INT, // Optional, maximum number of outgoing edges per node. default 16 - efConstruction: INT, // Optional, number of candidates during construction. default 200 - efRuntime: INT // Optional, number of candidates during search. default 10 -} -``` - -For example, to create a vector index over all `Product` nodes `description` attribute -use the following syntax: - -{% capture shell_19 %} -CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'} -{% endcapture %} - -{% capture python_19 %} -graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}") -{% endcapture %} - -{% capture javascript_19 %} -await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); -{% endcapture %} - -{% capture java_19 %} -graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); -{% endcapture %} - -{% capture rust_19 %} -graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="vector_create_node_tabs" shell=shell_19 python=python_19 javascript=javascript_19 java=java_19 rust=rust_19 %} - -Similarly to create a vector index over all `Call` relationships `summary` attribute -use the following syntax: - -{% capture shell_20 %} -CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'} -{% endcapture %} - -{% capture python_20 %} -graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}") -{% endcapture %} - -{% capture javascript_20 %} -await graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); -{% endcapture %} - -{% capture java_20 %} -graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); -{% endcapture %} - -{% capture rust_20 %} -graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="vector_create_relation_tabs" shell=shell_20 python=python_20 javascript=javascript_20 java=java_20 rust=rust_20 %} - -Please note, when creating a vector index, both the vector dimension and similarity function -must be provided. At the moment the only supported similarity functions are 'euclidean' or 'cosine'. - -## Inserting vectors - -To create a new vector use the [vecf32](/cypher/functions#vector-functions) function -as follows: - -{% capture shell_21 %} -CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])}) -{% endcapture %} - -{% capture python_21 %} -graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})") -{% endcapture %} - -{% capture javascript_21 %} -await graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})"); -{% endcapture %} - -{% capture java_21 %} -graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})"); -{% endcapture %} - -{% capture rust_21 %} -graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="vector_insert_tabs" shell=shell_21 python=python_21 javascript=javascript_21 java=java_21 rust=rust_21 %} - -The above query creates a new `Product` node with a `description` attribute containing a vector. - -## Query vector index - -Vector indices are used to search for similar vectors to a given query vector -using the similarity function as a measure of "distance". - -To query the index use either `db.idx.vector.queryNodes` for node retrieval or -`db.idx.vector.queryRelationships` for relationships. - -```cypher -CALL db.idx.vector.queryNodes( - label: STRING, - attribute: STRING, - k: INTEGER, - query: VECTOR -) YIELD node, score -``` - -```cypher -CALL db.idx.vector.queryRelationships( - relationshipType: STRING, - attribute: STRING, - k: INTEGER, - query: VECTOR -) YIELD relationship, score -``` - -To query up to 10 similar `Product` descriptions to a given query description vector -issue the following procedure call: - -{% capture shell_22 %} -CALL db.idx.vector.queryNodes( - 'Product', - 'description', - 10, - vecf32(), - ) YIELD node -{% endcapture %} - -{% capture python_22 %} -result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node") -{% endcapture %} - -{% capture javascript_22 %} -const result = await graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node"); -{% endcapture %} - -{% capture java_22 %} -ResultSet result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node"); -{% endcapture %} - -{% capture rust_22 %} -let result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="vector_query_tabs" shell=shell_22 python=python_22 javascript=javascript_22 java=java_22 rust=rust_22 %} - -The procedure can yield both the indexed entity assigned to the found similar vector -in addition to a similarity score of that entity. - -## Deleting a vector index - -To remove a vector index, simply issue the `drop index` command as follows: - -```cypher -DROP VECTOR INDEX FOR () -``` - -For example, to drop the vector index over Product description, invoke: - -{% capture shell_23 %} -DROP VECTOR INDEX FOR (p:Product) ON (p.description) -{% endcapture %} - -{% capture python_23 %} -graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)") -{% endcapture %} - -{% capture javascript_23 %} -await graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)"); -{% endcapture %} - -{% capture java_23 %} -graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)"); -{% endcapture %} - -{% capture rust_23 %} -graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)").execute().await?; -{% endcapture %} - -{% include code_tabs.html id="vector_drop_tabs" shell=shell_23 python=python_23 javascript=javascript_23 java=java_23 rust=rust_23 %} diff --git a/cypher/indexing/fulltext-index.md b/cypher/indexing/fulltext-index.md new file mode 100644 index 00000000..28625634 --- /dev/null +++ b/cypher/indexing/fulltext-index.md @@ -0,0 +1,636 @@ +--- +title: "Full-text Index" +nav_order: 2 +description: > + FalkorDB provides full-text indices through procedure calls. +parent: "Indexing" +grand_parent: "Cypher Language" +--- + +# Full-text indexing + +FalkorDB leverages the indexing capabilities of [RediSearch](https://redis.io/docs/interact/search-and-query/) to provide full-text indices through procedure calls. + +## Creating a full-text index for a node label + +To construct a full-text index on the `title` property of all nodes with label `Movie`, use the syntax: + +{% capture shell_10 %} +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', 'title')" +{% endcapture %} + +{% capture python_10 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')") +{% endcapture %} + +{% capture javascript_10 %} +await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"); +{% endcapture %} + +{% capture java_10 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')"); +{% endcapture %} + +{% capture rust_10 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', 'title')").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_create_tabs" shell=shell_10 python=python_10 javascript=javascript_10 java=java_10 rust=rust_10 %} + +More properties can be added to this index by adding their names to the above set of arguments, or using this syntax again with the additional names. + +{% capture shell_11 %} +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')" +{% endcapture %} + +{% capture python_11 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')") +{% endcapture %} + +{% capture javascript_11 %} +await graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"); +{% endcapture %} + +{% capture java_11 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')"); +{% endcapture %} + +{% capture rust_11 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Person', 'firstName', 'lastName')").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_multi_property_tabs" shell=shell_11 python=python_11 javascript=javascript_11 java=java_11 rust=rust_11 %} + +Index configuration options: + +1. Language - Define which language to use for stemming text, which is adding the base form of a word to the index. This allows the query for "going" to also return results for "go" and "gone", for example. +2. Stopwords - These are words that are usually so common that they do not add much information to search, but take up a lot of space and CPU time in the index. + +To construct a full-text index on the `title` property using `German` language and using custom stopwords of all nodes with label `Movie`, use the syntax: + +{% capture shell_12 %} +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')" +{% endcapture %} + +{% capture python_12 %} +graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')") +{% endcapture %} + +{% capture javascript_12 %} +await graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"); +{% endcapture %} + +{% capture java_12 %} +graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')"); +{% endcapture %} + +{% capture rust_12 %} +graph.query("CALL db.idx.fulltext.createNodeIndex({ label: 'Movie', language: 'German', stopwords: ['a', 'ab'] }, 'title')").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_config_tabs" shell=shell_12 python=python_12 javascript=javascript_12 java=java_12 rust=rust_12 %} + +Additional field configuration options: + +1. Weight - The importance of the text in the field +2. Nostem - Skip stemming when indexing text +3. Phonetic - Enable phonetic search on the text + +To construct a full-text index on the `title` property with phonetic search of all nodes with label `Movie`, use the syntax: + +{% capture shell_13 %} +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})" +{% endcapture %} + +{% capture python_13 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})") +{% endcapture %} + +{% capture javascript_13 %} +await graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"); +{% endcapture %} + +{% capture java_13 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})"); +{% endcapture %} + +{% capture rust_13 %} +graph.query("CALL db.idx.fulltext.createNodeIndex('Movie', {field: 'title', phonetic: 'dm:en'})").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_phonetic_tabs" shell=shell_13 python=python_13 javascript=javascript_13 java=java_13 rust=rust_13 %} + +## Query Syntax and Features + +FalkorDB uses [RediSearch query syntax](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/query_syntax/) which provides powerful search capabilities including fuzzy matching, prefix matching, and tokenization. + +### Tokenization + +When text is indexed, it is automatically tokenized (split into words). By default, text is split on whitespace and punctuation. This allows you to search for individual words within larger text fields. + +For example, if you index a `title` property containing "The Lord of the Rings", you can search for any of the individual words like "Lord" or "Rings". + +### Prefix Matching + +Prefix matching allows you to search for words that start with a specific prefix using the `*` wildcard. This is useful for autocomplete functionality or when you want to match word variations. + +{% capture shell_prefix %} +# Find all movies with titles containing words starting with "Jun" +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title" +# This would match "Jungle", "June", "Junior", etc. +{% endcapture %} + +{% capture python_prefix %} +# Find all movies with titles containing words starting with "Jun" +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title") +for record in result: + print(record["node.title"]) +# This would match "Jungle", "June", "Junior", etc. +{% endcapture %} + +{% capture javascript_prefix %} +// Find all movies with titles containing words starting with "Jun" +const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title"); +for (const record of result.data) { + console.log(record["node.title"]); +} +// This would match "Jungle", "June", "Junior", etc. +{% endcapture %} + +{% capture java_prefix %} +// Find all movies with titles containing words starting with "Jun" +ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title"); +for (Record record : result) { + System.out.println(record.get("node.title")); +} +// This would match "Jungle", "June", "Junior", etc. +{% endcapture %} + +{% capture rust_prefix %} +// Find all movies with titles containing words starting with "Jun" +let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*') YIELD node RETURN node.title").execute().await?; +for record in result.data() { + println!("{}", record["node.title"]); +} +// This would match "Jungle", "June", "Junior", etc. +{% endcapture %} + +{% include code_tabs.html id="fulltext_prefix_tabs" shell=shell_prefix python=python_prefix javascript=javascript_prefix java=java_prefix rust=rust_prefix %} + +**Note:** Prefix matching only works at the end of a word (e.g., `Jun*`). The wildcard must appear at the end of the search term. + +### Fuzzy Matching + +Fuzzy matching allows you to find words that are similar to your search term, accounting for typos and spelling variations. Use the `%` symbol followed by the Levenshtein distance (number of character changes allowed). + +{% capture shell_fuzzy %} +# Find movies with titles containing words similar to "Jangle" (allowing 1 character difference) +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title" +# This would match "Jungle" (1 character different) + +# Allow up to 2 character differences +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title" +# This would also match "Jungle" (1 character missing) +{% endcapture %} + +{% capture python_fuzzy %} +# Find movies with titles containing words similar to "Jangle" (allowing 1 character difference) +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title") +for record in result: + print(record["node.title"]) +# This would match "Jungle" (1 character different) + +# Allow up to 2 character differences +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title") +# This would also match "Jungle" (1 character missing) +{% endcapture %} + +{% capture javascript_fuzzy %} +// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference) +const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title"); +for (const record of result.data) { + console.log(record["node.title"]); +} +// This would match "Jungle" (1 character different) + +// Allow up to 2 character differences +const result2 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title"); +// This would also match "Jungle" (1 character missing) +{% endcapture %} + +{% capture java_fuzzy %} +// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference) +ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title"); +for (Record record : result) { + System.out.println(record.get("node.title")); +} +// This would match "Jungle" (1 character different) + +// Allow up to 2 character differences +ResultSet result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title"); +// This would also match "Jungle" (1 character missing) +{% endcapture %} + +{% capture rust_fuzzy %} +// Find movies with titles containing words similar to "Jangle" (allowing 1 character difference) +let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jangle%1') YIELD node RETURN node.title").execute().await?; +for record in result.data() { + println!("{}", record["node.title"]); +} +// This would match "Jungle" (1 character different) + +// Allow up to 2 character differences +let result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', '%Jngle%2') YIELD node RETURN node.title").execute().await?; +// This would also match "Jungle" (1 character missing) +{% endcapture %} + +{% include code_tabs.html id="fulltext_fuzzy_tabs" shell=shell_fuzzy python=python_fuzzy javascript=javascript_fuzzy java=java_fuzzy rust=rust_fuzzy %} + +**Fuzzy matching syntax:** `%term%distance` where: +- `term` is the word to match +- `distance` is the maximum Levenshtein distance (1-3, default is 1 if not specified) + +**Note:** Fuzzy matching is computationally more expensive than exact or prefix matching, so use it judiciously on large datasets. + +### Combining Query Features + +You can combine multiple search terms using boolean operators: + +- `AND` (or space): All terms must match +- `OR` (`|`): At least one term must match +- `NOT` (`-`): Term must not be present + +{% capture shell_combined %} +# Find movies with "Jungle" AND "Book" in the title +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title" + +# Find movies with "Jungle" OR "Forest" in the title +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title" + +# Find movies with "Book" but NOT "Jungle" +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title" + +# Combine prefix and fuzzy matching: Find "Jun*" OR words similar to "Forst" +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title" +{% endcapture %} + +{% capture python_combined %} +# Find movies with "Jungle" AND "Book" in the title +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title") + +# Find movies with "Jungle" OR "Forest" in the title +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title") + +# Find movies with "Book" but NOT "Jungle" +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title") + +# Combine prefix and fuzzy matching +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title") +{% endcapture %} + +{% capture javascript_combined %} +// Find movies with "Jungle" AND "Book" in the title +const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title"); + +// Find movies with "Jungle" OR "Forest" in the title +const result2 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title"); + +// Find movies with "Book" but NOT "Jungle" +const result3 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title"); + +// Combine prefix and fuzzy matching +const result4 = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title"); +{% endcapture %} + +{% capture java_combined %} +// Find movies with "Jungle" AND "Book" in the title +ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title"); + +// Find movies with "Jungle" OR "Forest" in the title +ResultSet result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title"); + +// Find movies with "Book" but NOT "Jungle" +ResultSet result3 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title"); + +// Combine prefix and fuzzy matching +ResultSet result4 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title"); +{% endcapture %} + +{% capture rust_combined %} +// Find movies with "Jungle" AND "Book" in the title +let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle Book') YIELD node RETURN node.title").execute().await?; + +// Find movies with "Jungle" OR "Forest" in the title +let result2 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jungle|Forest') YIELD node RETURN node.title").execute().await?; + +// Find movies with "Book" but NOT "Jungle" +let result3 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book -Jungle') YIELD node RETURN node.title").execute().await?; + +// Combine prefix and fuzzy matching +let result4 = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Jun*|%Forst%1') YIELD node RETURN node.title").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_combined_tabs" shell=shell_combined python=python_combined javascript=javascript_combined java=java_combined rust=rust_combined %} + +For more advanced query syntax features, see the [RediSearch query syntax documentation](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/query_syntax/). + +## Utilizing a full-text index for a node label + +An index can be invoked to match any whole words contained within: + +{% capture shell_14 %} +GRAPH.QUERY DEMO_GRAPH +"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title" +1) 1) "node.title" +2) 1) 1) "The Jungle Book" + 2) 1) "The Book of Life" +3) 1) "Query internal execution time: 0.927409 milliseconds" +{% endcapture %} + +{% capture python_14 %} +result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title") +for record in result: + print(record["node.title"]) +# Output: +# The Jungle Book +# The Book of Life +{% endcapture %} + +{% capture javascript_14 %} +const result = await graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"); +for (const record of result.data) { + console.log(record["node.title"]); +} +// Output: +// The Jungle Book +// The Book of Life +{% endcapture %} + +{% capture java_14 %} +ResultSet result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title"); +for (Record record : result) { + System.out.println(record.get("node.title")); +} +// Output: +// The Jungle Book +// The Book of Life +{% endcapture %} + +{% capture rust_14 %} +let result = graph.query("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node.title").execute().await?; +for record in result.data() { + println!("{}", record["node.title"]); +} +// Output: +// The Jungle Book +// The Book of Life +{% endcapture %} + +{% include code_tabs.html id="fulltext_query_tabs" shell=shell_14 python=python_14 javascript=javascript_14 java=java_14 rust=rust_14 %} + +This CALL clause can be interleaved with other Cypher clauses to perform more elaborate manipulations: + +```sh +GRAPH.QUERY DEMO_GRAPH +"CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node AS m +WHERE m.genre = 'Adventure' +RETURN m ORDER BY m.rating" +1) 1) "m" +2) 1) 1) 1) 1) "id" + 2) (integer) 1168 + 2) 1) "labels" + 2) 1) "Movie" + 3) 1) "properties" + 2) 1) 1) "genre" + 2) "Adventure" + 2) 1) "rating" + 2) "7.6" + 3) 1) "votes" + 2) (integer) 151342 + 4) 1) "year" + 2) (integer) 2016 + 5) 1) "title" + 2) "The Jungle Book" +3) 1) "Query internal execution time: 0.226914 milliseconds" +``` + +In addition to yielding matching nodes, full-text index scans will return the score of each node. This is the [TF-IDF](https://redis.io/docs/interact/search-and-query/advanced-concepts/scoring/#tfidf-default) score of the node, which is informed by how many times the search terms appear in the node and how closely grouped they are. This can be observed in the example: + +```sh +GRAPH.QUERY DEMO_GRAPH +"CALL db.idx.fulltext.queryNodes('Node', 'hello world') YIELD node, score RETURN score, node.val" +1) 1) "score" + 2) "node.val" +2) 1) 1) "2" + 2) "hello world" + 2) 1) "1" + 2) "hello to a different world" +3) 1) "Cached execution: 1" + 2) "Query internal execution time: 0.335401 milliseconds" +``` + +## Deleting a full-text index for a node label + +For a node label, the full-text index deletion syntax is: + +{% capture shell_15 %} +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.drop('Movie')" +{% endcapture %} + +{% capture python_15 %} +graph.query("CALL db.idx.fulltext.drop('Movie')") +{% endcapture %} + +{% capture javascript_15 %} +await graph.query("CALL db.idx.fulltext.drop('Movie')"); +{% endcapture %} + +{% capture java_15 %} +graph.query("CALL db.idx.fulltext.drop('Movie')"); +{% endcapture %} + +{% capture rust_15 %} +graph.query("CALL db.idx.fulltext.drop('Movie')").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_drop_tabs" shell=shell_15 python=python_15 javascript=javascript_15 java=java_15 rust=rust_15 %} + +## Creating Full-Text indexing for Relation Labels +To create a full-text index on the name property of all relations with the label Manager and enable phonetic search, use the following syntax: + +{% capture shell_16 %} +GRAPH.QUERY DEMO_GRAPH "CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)" +{% endcapture %} + +{% capture python_16 %} +graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)") +{% endcapture %} + +{% capture javascript_16 %} +await graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"); +{% endcapture %} + +{% capture java_16 %} +graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)"); +{% endcapture %} + +{% capture rust_16 %} +graph.query("CREATE FULLTEXT INDEX FOR ()-[m:Manager]-() on (m.name)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_relation_create_tabs" shell=shell_16 python=python_16 javascript=javascript_16 java=java_16 rust=rust_16 %} +## Querying with a Full-Text Index +To search for specific words within the indexed relations, use: + +{% capture shell_17 %} +GRAPH.QUERY DEMO_GRAPH +"CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name" +{% endcapture %} + +{% capture python_17 %} +result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name") +{% endcapture %} + +{% capture javascript_17 %} +const result = await graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"); +{% endcapture %} + +{% capture java_17 %} +ResultSet result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name"); +{% endcapture %} + +{% capture rust_17 %} +let result = graph.query("CALL db.idx.fulltext.queryRelationships('Manager', 'Charlie Munger') YIELD relationship RETURN relationship.name").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_relation_query_tabs" shell=shell_17 python=python_17 javascript=javascript_17 java=java_17 rust=rust_17 %} + +## Deleting a Full-Text Index +To delete the full-text index for a specific relation label, use: + +{% capture shell_18 %} +GRAPH.QUERY DEMO_GRAPH "DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)" +{% endcapture %} + +{% capture python_18 %} +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)") +{% endcapture %} + +{% capture javascript_18 %} +await graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); +{% endcapture %} + +{% capture java_18 %} +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)"); +{% endcapture %} + +{% capture rust_18 %} +graph.query("DROP FULLTEXT INDEX FOR ()-[m:Manager]-() ON (m.name)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="fulltext_relation_drop_tabs" shell=shell_18 python=python_18 javascript=javascript_18 java=java_18 rust=rust_18 %} + +## Index Management + +### Listing Full-text Indexes + +To view all indexes (including full-text) in your graph, use: + +```cypher +CALL db.indexes() +``` + +This returns information about all indexes, with full-text indexes marked with type `FULLTEXT`. + +## Performance Tradeoffs and Best Practices + +### When to Use Full-text Indexes + +Full-text indexes are ideal for: +- **Text-heavy search**: Searching within large text fields like descriptions, articles, or comments +- **Partial word matching**: When users might not know the exact text +- **Fuzzy search**: Handling typos and spelling variations +- **Multi-word queries**: Searching for multiple terms with boolean logic + +### When NOT to Use Full-text Indexes + +Full-text indexes are not optimal for: +- **Exact numeric filtering**: Use range indexes instead for numeric comparisons +- **Exact-match queries**: Range indexes are more efficient for exact property matches +- **Small or structured data**: For short, well-defined strings, range indexes may be sufficient + +### Performance Considerations + +**Benefits:** +- Enables sophisticated text search capabilities (fuzzy, prefix, phonetic) +- Supports stemming and language-specific optimizations +- Returns relevance scores (TF-IDF) for ranking results + +**Costs:** +- **Write overhead**: Text must be tokenized and indexed on write +- **Storage**: Requires more space than range indexes due to tokenization and inverted indices +- **Configuration complexity**: Language, stopwords, and stemming settings affect results +- **Query performance**: Fuzzy matching is more expensive than exact matching + +**Recommendations:** +- Choose the correct language setting for proper stemming +- Configure appropriate stopwords for your use case +- Use prefix matching (`*`) for autocomplete rather than full fuzzy search when possible +- Test query performance with realistic data volumes +- Consider the tradeoff between index configurability and query performance + +### Configuration Best Practices + +**Language Selection:** +- Wrong language settings can produce poor stemming results +- Example: Searching "running" with English stemming finds "run", but German stemming won't + +**Stopwords:** +- Default stopwords are optimized for general text +- Customize stopwords for domain-specific applications (e.g., legal, medical, technical documents) +- Too many stopwords can hurt precision; too few increase index size + +**Phonetic Search:** +- Useful for name searches and when spelling variations are common +- Increases index size and query time +- Double Metaphone (`dm:en`) is recommended for English + +## Verifying Full-text Index Usage + +Use `GRAPH.EXPLAIN` to verify that full-text queries use the index: + +{% capture shell_ft_verify %} +# Check if full-text index is used +GRAPH.EXPLAIN DEMO_GRAPH "CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node" +# Output shows: ProcedureCall | db.idx.fulltext.queryNodes +{% endcapture %} + +{% capture python_ft_verify %} +# Check if full-text index is used +result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node") +print(result) +# Output shows: ProcedureCall | db.idx.fulltext.queryNodes +{% endcapture %} + +{% capture javascript_ft_verify %} +// Check if full-text index is used +const result = await graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node"); +console.log(result); +// Output shows: ProcedureCall | db.idx.fulltext.queryNodes +{% endcapture %} + +{% capture java_ft_verify %} +// Check if full-text index is used +String result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node"); +System.out.println(result); +// Output shows: ProcedureCall | db.idx.fulltext.queryNodes +{% endcapture %} + +{% capture rust_ft_verify %} +// Check if full-text index is used +let result = graph.explain("CALL db.idx.fulltext.queryNodes('Movie', 'Book') YIELD node RETURN node").execute().await?; +println!("{}", result); +// Output shows: ProcedureCall | db.idx.fulltext.queryNodes +{% endcapture %} + +{% include code_tabs.html id="fulltext_verify_tabs" shell=shell_ft_verify python=python_ft_verify javascript=javascript_ft_verify java=java_ft_verify rust=rust_ft_verify %} diff --git a/cypher/indexing/index.md b/cypher/indexing/index.md new file mode 100644 index 00000000..45acf1f1 --- /dev/null +++ b/cypher/indexing/index.md @@ -0,0 +1,34 @@ +--- +title: "Indexing" +nav_order: 21 +description: > + FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed. +parent: "Cypher Language" +has_children: true +redirect_from: + - /cypher/indexing.html +--- + +# Indexing + +FalkorDB provides multiple types of indexes to optimize query performance and enable efficient data retrieval. Each index type is designed for specific use cases and data patterns. + +## Index Types + +FalkorDB supports the following index types: + +### [Range Index](./range-index) + +Range indexes support single-property indexes for node labels and relationship types. String, numeric, and geospatial data types can be indexed. These indexes automatically optimize queries with filters on indexed properties. + +### [Full-text Index](./fulltext-index) + +Full-text indexes leverage RediSearch capabilities to provide powerful text search functionality. They support features like stemming, stopwords, phonetic search, and scoring based on TF-IDF. + +### [Vector Index](./vector-index) + +Vector indexes enable similarity search on vector embeddings. These indexes are essential for AI and machine learning applications, supporting operations like nearest neighbor search with configurable similarity functions (euclidean or cosine). + +--- + +Choose an index type from the navigation menu to learn more about creating, querying, and managing that specific type of index. diff --git a/cypher/indexing/range-index.md b/cypher/indexing/range-index.md new file mode 100644 index 00000000..d4438919 --- /dev/null +++ b/cypher/indexing/range-index.md @@ -0,0 +1,488 @@ +--- +title: "Range Index" +nav_order: 1 +description: > + FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed. +parent: "Indexing" +grand_parent: "Cypher Language" +--- + +# Range Index + +FalkorDB supports single-property indexes for node labels and for relationship type. String, numeric, and geospatial data types can be indexed. + +## Supported Data Types + +Range indexes support the following data types: +- **String**: Text values for exact matching and range queries +- **Numeric**: Integer and floating-point numbers for range comparisons +- **Geospatial**: Point data types for location-based queries +- **Arrays**: Single-property arrays containing scalar values (integers, floats, strings) + +**Note**: Complex types like nested arrays, maps, or vectors are not supported for range indexing. + +## Creating an index for a node label + +For a node label, the index creation syntax is: + +{% capture shell_0 %} +GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)" +{% endcapture %} + +{% capture python_0 %} +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)") +{% endcapture %} + +{% capture javascript_0 %} +await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); +{% endcapture %} + +{% capture java_0 %} +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); +{% endcapture %} + +{% capture rust_0 %} +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="create_index_tabs" shell=shell_0 python=python_0 javascript=javascript_0 java=java_0 rust=rust_0 %} + +An old syntax is also supported: + +{% capture shell_1 %} +GRAPH.QUERY DEMO_GRAPH "CREATE INDEX ON :Person(age)" +{% endcapture %} + +{% capture python_1 %} +graph.query("CREATE INDEX ON :Person(age)") +{% endcapture %} + +{% capture javascript_1 %} +await graph.query("CREATE INDEX ON :Person(age)"); +{% endcapture %} + +{% capture java_1 %} +graph.query("CREATE INDEX ON :Person(age)"); +{% endcapture %} + +{% capture rust_1 %} +graph.query("CREATE INDEX ON :Person(age)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="old_syntax_tabs" shell=shell_1 python=python_1 javascript=javascript_1 java=java_1 rust=rust_1 %} + +After an index is explicitly created, it will automatically be used by queries that reference that label and any indexed property in a filter. + +{% capture shell_2 %} +GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 80 RETURN p" +1) "Results" +2) " Project" +3) " Index Scan | (p:Person)" +{% endcapture %} + +{% capture python_2 %} +result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p") +print(result) +# Output: +# Results +# Project +# Index Scan | (p:Person) +{% endcapture %} + +{% capture javascript_2 %} +const result = await graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p"); +console.log(result); +// Output: +// Results +// Project +// Index Scan | (p:Person) +{% endcapture %} + +{% capture java_2 %} +String result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p"); +System.out.println(result); +// Output: +// Results +// Project +// Index Scan | (p:Person) +{% endcapture %} + +{% capture rust_2 %} +let result = graph.explain("MATCH (p:Person) WHERE p.age > 80 RETURN p").execute().await?; +println!("{}", result); +// Output: +// Results +// Project +// Index Scan | (p:Person) +{% endcapture %} + +{% include code_tabs.html id="explain_tabs" shell=shell_2 python=python_2 javascript=javascript_2 java=java_2 rust=rust_2 %} + +This can significantly improve the runtime of queries with very specific filters. An index on `:employer(name)`, for example, will dramatically benefit the query: + +{% capture shell_3 %} +GRAPH.QUERY DEMO_GRAPH +"MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p" +{% endcapture %} + +{% capture python_3 %} +result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p") +{% endcapture %} + +{% capture javascript_3 %} +const result = await graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"); +{% endcapture %} + +{% capture java_3 %} +ResultSet result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p"); +{% endcapture %} + +{% capture rust_3 %} +let result = graph.query("MATCH (:Employer {name: 'Dunder Mifflin'})-[:EMPLOYS]->(p:Person) RETURN p").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="employer_query_tabs" shell=shell_3 python=python_3 javascript=javascript_3 java=java_3 rust=rust_3 %} + +An example of utilizing a geospatial index to find `Employer` nodes within 5 kilometers of Scranton are: + +{% capture shell_4 %} +GRAPH.QUERY DEMO_GRAPH +"WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e" +{% endcapture %} + +{% capture python_4 %} +result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e") +{% endcapture %} + +{% capture javascript_4 %} +const result = await graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"); +{% endcapture %} + +{% capture java_4 %} +ResultSet result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e"); +{% endcapture %} + +{% capture rust_4 %} +let result = graph.query("WITH point({latitude:41.4045886, longitude:-75.6969532}) AS scranton MATCH (e:Employer) WHERE distance(e.location, scranton) < 5000 RETURN e").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="geospatial_tabs" shell=shell_4 python=python_4 javascript=javascript_4 java=java_4 rust=rust_4 %} + +Geospatial indexes can currently only be leveraged with `<` and `<=` filters; matching nodes outside the given radius are matched using conventional traversal. + +## Creating an index for a relationship type + +For a relationship type, the index creation syntax is: + +{% capture shell_5 %} +GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)" +{% endcapture %} + +{% capture python_5 %} +graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)") +{% endcapture %} + +{% capture javascript_5 %} +await graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"); +{% endcapture %} + +{% capture java_5 %} +graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)"); +{% endcapture %} + +{% capture rust_5 %} +graph.query("CREATE INDEX FOR ()-[f:FOLLOW]-() ON (f.created_at)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="relationship_index_tabs" shell=shell_5 python=python_5 javascript=javascript_5 java=java_5 rust=rust_5 %} + +Then the execution plan for using the index: + +{% capture shell_6 %} +GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp" +1) "Results" +2) " Project" +3) " Edge By Index Scan | [f:FOLLOW]" +4) " Node By Index Scan | (p:Person)" +{% endcapture %} + +{% capture python_6 %} +result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp") +print(result) +# Output: +# Results +# Project +# Edge By Index Scan | [f:FOLLOW] +# Node By Index Scan | (p:Person) +{% endcapture %} + +{% capture javascript_6 %} +const result = await graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"); +console.log(result); +// Output: +// Results +// Project +// Edge By Index Scan | [f:FOLLOW] +// Node By Index Scan | (p:Person) +{% endcapture %} + +{% capture java_6 %} +String result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp"); +System.out.println(result); +// Output: +// Results +// Project +// Edge By Index Scan | [f:FOLLOW] +// Node By Index Scan | (p:Person) +{% endcapture %} + +{% capture rust_6 %} +let result = graph.explain("MATCH (p:Person {id: 0})-[f:FOLLOW]->(fp) WHERE 0 < f.created_at AND f.created_at < 1000 RETURN fp").execute().await?; +println!("{}", result); +// Output: +// Results +// Project +// Edge By Index Scan | [f:FOLLOW] +// Node By Index Scan | (p:Person) +{% endcapture %} + +{% include code_tabs.html id="relationship_explain_tabs" shell=shell_6 python=python_6 javascript=javascript_6 java=java_6 rust=rust_6 %} + +This can significantly improve the runtime of queries that traverse super nodes or when we want to start traverse from relationships. + +## Deleting an index for a node label + +For a node label, the index deletion syntax is: + +{% capture shell_7 %} +GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :Person(age)" +{% endcapture %} + +{% capture python_7 %} +graph.query("DROP INDEX ON :Person(age)") +{% endcapture %} + +{% capture javascript_7 %} +await graph.query("DROP INDEX ON :Person(age)"); +{% endcapture %} + +{% capture java_7 %} +graph.query("DROP INDEX ON :Person(age)"); +{% endcapture %} + +{% capture rust_7 %} +graph.query("DROP INDEX ON :Person(age)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="drop_node_index_tabs" shell=shell_7 python=python_7 javascript=javascript_7 java=java_7 rust=rust_7 %} + +## Deleting an index for a relationship type + +For a relationship type, the index deletion syntax is: + +{% capture shell_8 %} +GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :FOLLOW(created_at)" +{% endcapture %} + +{% capture python_8 %} +graph.query("DROP INDEX ON :FOLLOW(created_at)") +{% endcapture %} + +{% capture javascript_8 %} +await graph.query("DROP INDEX ON :FOLLOW(created_at)"); +{% endcapture %} + +{% capture java_8 %} +graph.query("DROP INDEX ON :FOLLOW(created_at)"); +{% endcapture %} + +{% capture rust_8 %} +graph.query("DROP INDEX ON :FOLLOW(created_at)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="drop_relationship_index_tabs" shell=shell_8 python=python_8 javascript=javascript_8 java=java_8 rust=rust_8 %} + +## Array Indices + +FalkorDB supports indexing on array properties containing scalar values (e.g., integers, floats, strings), enabling efficient lookups for elements within such arrays. + +Note: Complex types like nested arrays, maps, or vectors are not supported for indexing. + +The following example demonstrates how to index and search an array property: + +{% capture shell_9 %} +# Create a node with an array property +GRAPH.QUERY DEMO_GRAPH "CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})" + +# Create an index on the array property +GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.samples)" + +# Use the index to search for nodes containing a specific value in the array +GRAPH.QUERY DEMO_GRAPH "MATCH (p:Person) WHERE 90 IN p.samples RETURN p" +{% endcapture %} + +{% capture python_9 %} +# Create a node with an array property +graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})") + +# Create an index on the array property +graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)") + +# Use the index to search for nodes containing a specific value in the array +result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p") +{% endcapture %} + +{% capture javascript_9 %} +// Create a node with an array property +await graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"); + +// Create an index on the array property +await graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)"); + +// Use the index to search for nodes containing a specific value in the array +const result = await graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p"); +{% endcapture %} + +{% capture java_9 %} +// Create a node with an array property +graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})"); + +// Create an index on the array property +graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)"); + +// Use the index to search for nodes containing a specific value in the array +ResultSet result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p"); +{% endcapture %} + +{% capture rust_9 %} +// Create a node with an array property +graph.query("CREATE (:Person {samples: [-21, 30.5, 0, 90, 3.14]})").execute().await?; + +// Create an index on the array property +graph.query("CREATE INDEX FOR (p:Person) ON (p.samples)").execute().await?; + +// Use the index to search for nodes containing a specific value in the array +let result = graph.query("MATCH (p:Person) WHERE 90 IN p.samples RETURN p").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="array_index_tabs" shell=shell_9 python=python_9 javascript=javascript_9 java=java_9 rust=rust_9 %} + +## Verifying Index Usage + +To verify that an index is being used by your query, use `GRAPH.EXPLAIN` before and after creating the index: + +{% capture shell_verify %} +# Before creating the index +GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p" +# Output shows: Label Scan | (p:Person) + +# Create the index +GRAPH.QUERY DEMO_GRAPH "CREATE INDEX FOR (p:Person) ON (p.age)" + +# After creating the index +GRAPH.EXPLAIN DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p" +# Output now shows: Index Scan | (p:Person) +{% endcapture %} + +{% capture python_verify %} +# Before creating the index +result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p") +print(result) # Shows: Label Scan | (p:Person) + +# Create the index +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)") + +# After creating the index +result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p") +print(result) # Now shows: Index Scan | (p:Person) +{% endcapture %} + +{% capture javascript_verify %} +// Before creating the index +let result = await graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p"); +console.log(result); // Shows: Label Scan | (p:Person) + +// Create the index +await graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); + +// After creating the index +result = await graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p"); +console.log(result); // Now shows: Index Scan | (p:Person) +{% endcapture %} + +{% capture java_verify %} +// Before creating the index +String result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p"); +System.out.println(result); // Shows: Label Scan | (p:Person) + +// Create the index +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)"); + +// After creating the index +result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p"); +System.out.println(result); // Now shows: Index Scan | (p:Person) +{% endcapture %} + +{% capture rust_verify %} +// Before creating the index +let result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p").execute().await?; +println!("{}", result); // Shows: Label Scan | (p:Person) + +// Create the index +graph.query("CREATE INDEX FOR (p:Person) ON (p.age)").execute().await?; + +// After creating the index +let result = graph.explain("MATCH (p:Person) WHERE p.age > 30 RETURN p").execute().await?; +println!("{}", result); // Now shows: Index Scan | (p:Person) +{% endcapture %} + +{% include code_tabs.html id="verify_index_tabs" shell=shell_verify python=python_verify javascript=javascript_verify java=java_verify rust=rust_verify %} + +## Index Management + +### Listing Existing Indexes + +To view all indexes in your graph, use the `db.indexes()` procedure: + +```cypher +CALL db.indexes() +``` + +This returns information about all indexes including their type (RANGE), entity type (node/relationship), labels, and properties. + +## Performance Tradeoffs and Best Practices + +### When to Use Range Indexes + +Range indexes are ideal for: +- **Filtering by specific values**: Queries with equality filters (e.g., `WHERE p.name = 'Alice'`) +- **Range queries**: Numeric or string comparisons (e.g., `WHERE p.age > 30`, `WHERE p.name >= 'A' AND p.name < 'B'`) +- **Geospatial queries**: Finding entities within a certain distance +- **Array membership**: Checking if a value exists in an array property + +### Performance Considerations + +**Benefits:** +- Dramatically improves query performance for filtered searches +- Reduces the number of nodes/relationships that need to be scanned +- Enables efficient range scans and point lookups + +**Costs:** +- **Write overhead**: Every insert or update to an indexed property requires updating the index +- **Storage**: Indexes consume additional memory and disk space +- **Maintenance**: Index structures need to be maintained during graph modifications + +**Recommendations:** +- Index properties that are frequently used in `WHERE` clauses +- Avoid indexing properties that are rarely queried or have high write frequency +- For properties with very few distinct values (low cardinality), indexes may not provide significant benefits +- Monitor query performance with `GRAPH.PROFILE` to validate index effectiveness + +### Example: Profiling Index Performance + +```cypher +# Profile query to see actual execution metrics +GRAPH.PROFILE DEMO_GRAPH "MATCH (p:Person) WHERE p.age > 30 RETURN p" +``` + +This shows detailed timing information and confirms whether the index was used. diff --git a/cypher/indexing/vector-index.md b/cypher/indexing/vector-index.md new file mode 100644 index 00000000..b2788ff1 --- /dev/null +++ b/cypher/indexing/vector-index.md @@ -0,0 +1,421 @@ +--- +title: "Vector Index" +nav_order: 3 +description: > + FalkorDB supports vector indexes for similarity search on vector embeddings, essential for AI and machine learning applications. +parent: "Indexing" +grand_parent: "Cypher Language" +--- + +# Vector indexing + +With the introduction of the `vector` data-type a new type of index was introduced. +A vector index is a dedicated index for indexing and searching through vectors. + +To create this type of index use the following syntax: + +```cypher +CREATE VECTOR INDEX FOR ON OPTIONS +``` + +The options are: +``` +{ + dimension: INT, // Required, length of the vector to be indexed + similarityFunction: STRING, // Required, currently only euclidean or cosine are allowed + M: INT, // Optional, maximum number of outgoing edges per node. default 16 + efConstruction: INT, // Optional, number of candidates during construction. default 200 + efRuntime: INT // Optional, number of candidates during search. default 10 +} +``` + +For example, to create a vector index over all `Product` nodes `description` attribute +use the following syntax: + +{% capture shell_19 %} +CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'} +{% endcapture %} + +{% capture python_19 %} +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}") +{% endcapture %} + +{% capture javascript_19 %} +await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); +{% endcapture %} + +{% capture java_19 %} +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); +{% endcapture %} + +{% capture rust_19 %} +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.description) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="vector_create_node_tabs" shell=shell_19 python=python_19 javascript=javascript_19 java=java_19 rust=rust_19 %} + +Similarly to create a vector index over all `Call` relationships `summary` attribute +use the following syntax: + +{% capture shell_20 %} +CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'} +{% endcapture %} + +{% capture python_20 %} +graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}") +{% endcapture %} + +{% capture javascript_20 %} +await graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); +{% endcapture %} + +{% capture java_20 %} +graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}"); +{% endcapture %} + +{% capture rust_20 %} +graph.query("CREATE VECTOR INDEX FOR ()-[e:Call]->() ON (e.summary) OPTIONS {dimension:128, similarityFunction:'euclidean'}").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="vector_create_relation_tabs" shell=shell_20 python=python_20 javascript=javascript_20 java=java_20 rust=rust_20 %} + +**Important**: When creating a vector index, both the vector dimension and similarity function must be provided. Currently, the only supported similarity functions are 'euclidean' or 'cosine'. + +## Understanding Vector Index Parameters + +### Required Parameters + +- **dimension**: The length of the vectors to be indexed. Must match the dimensionality of your embeddings (e.g., 128, 384, 768, 1536). +- **similarityFunction**: The distance metric used for similarity search: + - `euclidean`: Euclidean distance (L2 norm). Best for embeddings where magnitude matters. + - `cosine`: Cosine similarity. Best for normalized embeddings where direction matters more than magnitude. + +### Optional Parameters + +These parameters control the HNSW (Hierarchical Navigable Small World) index structure: + +- **M** (default: 16): Maximum number of connections per node in the graph + - Higher values improve recall but increase memory usage and build time + - Recommended range: 12-48 + - Use 16-32 for most applications + +- **efConstruction** (default: 200): Number of candidates evaluated during index construction + - Higher values improve index quality but slow down indexing + - Recommended range: 100-400 + - Use 200-300 for balanced quality/speed + +- **efRuntime** (default: 10): Number of candidates evaluated during search + - Higher values improve recall but slow down queries + - Can be adjusted per-query for speed/accuracy tradeoffs + - Recommended: Start with 10, increase if recall is insufficient + +## Inserting vectors + +To create a new vector use the [vecf32](/cypher/functions#vector-functions) function +as follows: + +{% capture shell_21 %} +CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])}) +{% endcapture %} + +{% capture python_21 %} +graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})") +{% endcapture %} + +{% capture javascript_21 %} +await graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})"); +{% endcapture %} + +{% capture java_21 %} +graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})"); +{% endcapture %} + +{% capture rust_21 %} +graph.query("CREATE (p: Product {description: vecf32([2.1, 0.82, 1.3])})").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="vector_insert_tabs" shell=shell_21 python=python_21 javascript=javascript_21 java=java_21 rust=rust_21 %} + +The above query creates a new `Product` node with a `description` attribute containing a vector. + +## Query vector index + +Vector indices are used to search for similar vectors to a given query vector +using the similarity function as a measure of "distance". + +To query the index use either `db.idx.vector.queryNodes` for node retrieval or +`db.idx.vector.queryRelationships` for relationships. + +```cypher +CALL db.idx.vector.queryNodes( + label: STRING, + attribute: STRING, + k: INTEGER, + query: VECTOR +) YIELD node, score +``` + +```cypher +CALL db.idx.vector.queryRelationships( + relationshipType: STRING, + attribute: STRING, + k: INTEGER, + query: VECTOR +) YIELD relationship, score +``` + +To query up to 10 similar `Product` descriptions to a given query description vector +issue the following procedure call: + +{% capture shell_22 %} +CALL db.idx.vector.queryNodes( + 'Product', + 'description', + 10, + vecf32(), + ) YIELD node +{% endcapture %} + +{% capture python_22 %} +result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node") +{% endcapture %} + +{% capture javascript_22 %} +const result = await graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node"); +{% endcapture %} + +{% capture java_22 %} +ResultSet result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node"); +{% endcapture %} + +{% capture rust_22 %} +let result = graph.query("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32()) YIELD node").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="vector_query_tabs" shell=shell_22 python=python_22 javascript=javascript_22 java=java_22 rust=rust_22 %} + +The procedure can yield both the indexed entity assigned to the found similar vector +in addition to a similarity score of that entity. + +## Deleting a vector index + +To remove a vector index, simply issue the `drop index` command as follows: + +```cypher +DROP VECTOR INDEX FOR () +``` + +For example, to drop the vector index over Product description, invoke: + +{% capture shell_23 %} +DROP VECTOR INDEX FOR (p:Product) ON (p.description) +{% endcapture %} + +{% capture python_23 %} +graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)") +{% endcapture %} + +{% capture javascript_23 %} +await graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)"); +{% endcapture %} + +{% capture java_23 %} +graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)"); +{% endcapture %} + +{% capture rust_23 %} +graph.query("DROP VECTOR INDEX FOR (p:Product) ON (p.description)").execute().await?; +{% endcapture %} + +{% include code_tabs.html id="vector_drop_tabs" shell=shell_23 python=python_23 javascript=javascript_23 java=java_23 rust=rust_23 %} + +## Index Management + +### Listing Vector Indexes + +To view all indexes (including vector) in your graph, use: + +```cypher +CALL db.indexes() +``` + +Vector indexes are marked with type `VECTOR` and show the dimension and similarity function in the options field. + +## Verifying Vector Index Usage + +To verify that a vector index is being used, examine the query execution plan: + +{% capture shell_vec_verify %} +# Query using vector index +GRAPH.EXPLAIN DEMO_GRAPH "CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node" +# Output shows: ProcedureCall | db.idx.vector.queryNodes +{% endcapture %} + +{% capture python_vec_verify %} +# Query using vector index +query_vector = [2.1, 0.82, 1.3] +result = graph.explain(f"CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32({query_vector})) YIELD node RETURN node") +print(result) +# Output shows: ProcedureCall | db.idx.vector.queryNodes +{% endcapture %} + +{% capture javascript_vec_verify %} +// Query using vector index +const queryVector = [2.1, 0.82, 1.3]; +const result = await graph.explain(`CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([${queryVector}])) YIELD node RETURN node`); +console.log(result); +// Output shows: ProcedureCall | db.idx.vector.queryNodes +{% endcapture %} + +{% capture java_vec_verify %} +// Query using vector index +float[] queryVector = {2.1f, 0.82f, 1.3f}; +String result = graph.explain("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node"); +System.out.println(result); +// Output shows: ProcedureCall | db.idx.vector.queryNodes +{% endcapture %} + +{% capture rust_vec_verify %} +// Query using vector index +let result = graph.explain("CALL db.idx.vector.queryNodes('Product', 'description', 10, vecf32([2.1, 0.82, 1.3])) YIELD node RETURN node").execute().await?; +println!("{}", result); +// Output shows: ProcedureCall | db.idx.vector.queryNodes +{% endcapture %} + +{% include code_tabs.html id="vector_verify_tabs" shell=shell_vec_verify python=python_vec_verify javascript=javascript_vec_verify java=java_vec_verify rust=rust_vec_verify %} + +## Performance Tradeoffs and Best Practices + +### When to Use Vector Indexes + +Vector indexes are essential for: +- **Semantic search**: Finding similar items based on meaning, not just keywords +- **Recommendation systems**: Discovering similar products, content, or users +- **RAG (Retrieval Augmented Generation)**: Retrieving relevant context for LLMs +- **Duplicate detection**: Finding near-duplicate items based on embeddings +- **Image/audio similarity**: When using vision or audio embedding models + +### Performance Considerations + +**Benefits:** +- Enables efficient approximate nearest neighbor (ANN) search +- Scales to millions of vectors with sub-linear query time +- Supports both node and relationship vectors + +**Costs:** +- **Memory usage**: Vector indexes are memory-intensive + - A 1M vector index with 768 dimensions (float32) requires ~3GB of memory + - Formula: `vectors × dimensions × 4 bytes + HNSW overhead (~20%)` +- **Build time**: Index construction can be slow for large datasets +- **Approximate results**: Returns approximate (not exact) nearest neighbors +- **No support for filtering**: Vector queries don't combine well with property filters + +**Recommendations:** +- Choose appropriate vector dimensions (balance between quality and cost) +- Use cosine similarity for normalized embeddings (e.g., from OpenAI, Sentence Transformers) +- Use euclidean distance for unnormalized data +- Tune M and efConstruction based on your accuracy requirements +- Consider batch indexing for large datasets +- Monitor memory usage carefully + +### Similarity Function Tradeoffs + +**Cosine Similarity:** +- Best for: Text embeddings, normalized vectors +- Measures: Angular distance between vectors +- Range: -1 to 1 (1 = identical direction) +- Use when: Vector magnitude is not meaningful + +**Euclidean Distance:** +- Best for: Unnormalized data, physical measurements +- Measures: Straight-line distance between vectors +- Range: 0 to ∞ (0 = identical) +- Use when: Both direction and magnitude matter + +### Example: Realistic Vector Search + +{% capture shell_vec_example %} +# Create vector index for product embeddings +GRAPH.QUERY DEMO_GRAPH "CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}" + +# Insert products with embeddings (embeddings would come from your model) +GRAPH.QUERY DEMO_GRAPH "CREATE (p:Product {name: 'Laptop', embedding: vecf32([0.1, 0.2, ...])})" + +# Search for similar products +GRAPH.QUERY DEMO_GRAPH "CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32([0.15, 0.18, ...])) YIELD node, score RETURN node.name, score ORDER BY score DESC" +{% endcapture %} + +{% capture python_vec_example %} +# Create vector index for product embeddings +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}") + +# Insert products with embeddings (embeddings would come from your model) +embedding = model.encode("laptop computer") # Your embedding model +graph.query(f"CREATE (p:Product {{name: 'Laptop', embedding: vecf32({embedding.tolist()})}})") + +# Search for similar products +query_embedding = model.encode("notebook pc") +result = graph.query(f"CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32({query_embedding.tolist()})) YIELD node, score RETURN node.name, score ORDER BY score DESC") +for record in result.result_set: + print(f"Product: {record[0]}, Similarity: {record[1]}") +{% endcapture %} + +{% capture javascript_vec_example %} +// Create vector index for product embeddings +await graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}"); + +// Insert products with embeddings (embeddings would come from your model) +const embedding = await model.encode("laptop computer"); // Your embedding model +await graph.query(`CREATE (p:Product {name: 'Laptop', embedding: vecf32([${embedding}])})`); + +// Search for similar products +const queryEmbedding = await model.encode("notebook pc"); +const result = await graph.query(`CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32([${queryEmbedding}])) YIELD node, score RETURN node.name, score ORDER BY score DESC`); +for (const record of result.data) { + console.log(`Product: ${record['node.name']}, Similarity: ${record['score']}`); +} +{% endcapture %} + +{% capture java_vec_example %} +// Create vector index for product embeddings +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}"); + +// Insert products with embeddings (embeddings would come from your model) +float[] embedding = model.encode("laptop computer"); // Your embedding model +graph.query(String.format("CREATE (p:Product {name: 'Laptop', embedding: vecf32(%s)})", Arrays.toString(embedding))); + +// Search for similar products +float[] queryEmbedding = model.encode("notebook pc"); +ResultSet result = graph.query(String.format("CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32(%s)) YIELD node, score RETURN node.name, score ORDER BY score DESC", Arrays.toString(queryEmbedding))); +for (Record record : result) { + System.out.printf("Product: %s, Similarity: %s%n", record.get("node.name"), record.get("score")); +} +{% endcapture %} + +{% capture rust_vec_example %} +// Create vector index for product embeddings +graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimension:768, similarityFunction:'cosine', M:32, efConstruction:200}").execute().await?; + +// Insert products with embeddings (embeddings would come from your model) +let embedding = model.encode("laptop computer"); // Your embedding model +graph.query(&format!("CREATE (p:Product {{name: 'Laptop', embedding: vecf32({:?})}})", embedding)).execute().await?; + +// Search for similar products +let query_embedding = model.encode("notebook pc"); +let result = graph.query(&format!("CALL db.idx.vector.queryNodes('Product', 'embedding', 5, vecf32({:?})) YIELD node, score RETURN node.name, score ORDER BY score DESC", query_embedding)).execute().await?; +for record in result.data() { + println!("Product: {}, Similarity: {}", record["node.name"], record["score"]); +} +{% endcapture %} + +{% include code_tabs.html id="vector_example_tabs" shell=shell_vec_example python=python_vec_example javascript=javascript_vec_example java=java_vec_example rust=rust_vec_example %} + +### Troubleshooting + +**Common Issues:** + +1. **Dimension mismatch**: Ensure all vectors have the same dimension as specified in the index +2. **Wrong similarity function**: Use cosine for normalized vectors, euclidean for unnormalized +3. **Poor recall**: Increase efRuntime or efConstruction parameters +4. **Slow queries**: Decrease efRuntime or reduce k (number of results) +5. **High memory usage**: Reduce M parameter or use lower-dimensional embeddings diff --git a/cypher/procedures.md b/cypher/procedures.md index 12d15350..0d2f9aba 100644 --- a/cypher/procedures.md +++ b/cypher/procedures.md @@ -39,9 +39,9 @@ GRAPH.QUERY social "CALL db.labels() YIELD label" | db.idx.fulltext.createNodeIndex | `label`, `property` [, `property` ...] | none | Builds a full-text searchable index on a label and the 1 or more specified properties. | | db.idx.fulltext.drop | `label` | none | Deletes the full-text index associated with the given label. | | db.idx.fulltext.queryNodes | `label`, `string` | `node`, `score` | Retrieve all nodes that contain the specified string in the full-text indexes on the given label. | -| db.idx.fulltext.queryRelationships | `relationshipType`, `string` | `relationship`, `score` | Retrieve all relationships that contain the specified string in the full-text indexes on the given relationship type. See [Full-Text Indexing](/cypher/indexing#full-text-indexing) for details. | -| db.idx.vector.queryNodes | `label`, `attribute`, `k`, `query` | `node`, `score` | Retrieve up to k nodes with vectors most similar to the query vector using the specified label and attribute. See [Vector Indexing](/cypher/indexing#vector-indexing) for details. | -| db.idx.vector.queryRelationships | `relationshipType`, `attribute`, `k`, `query` | `relationship`, `score` | Retrieve up to k relationships with vectors most similar to the query vector using the specified relationship type and attribute. See [Vector Indexing](/cypher/indexing#vector-indexing) for details. | +| db.idx.fulltext.queryRelationships | `relationshipType`, `string` | `relationship`, `score` | Retrieve all relationships that contain the specified string in the full-text indexes on the given relationship type. See [Full-Text Indexing](/cypher/indexing/fulltext-index) for details. | +| db.idx.vector.queryNodes | `label`, `attribute`, `k`, `query` | `node`, `score` | Retrieve up to k nodes with vectors most similar to the query vector using the specified label and attribute. See [Vector Indexing](/cypher/indexing/vector-index) for details. | +| db.idx.vector.queryRelationships | `relationshipType`, `attribute`, `k`, `query` | `relationship`, `score` | Retrieve up to k relationships with vectors most similar to the query vector using the specified relationship type and attribute. See [Vector Indexing](/cypher/indexing/vector-index) for details. | | algo.pageRank | `label`, `relationship-type` | `node`, `score` | Runs the pagerank algorithm over nodes of given label, considering only edges of given relationship type. | | algo.BFS | `source-node`, `max-level`, `relationship-type` | `nodes`, `edges` | Performs BFS to find all nodes connected to the source. A `max level` of 0 indicates unlimited and a non-NULL `relationship-type` defines the relationship type that may be traversed. See [BFS Algorithm](/algorithms/bfs) for details. | | algo.MSF | `config` | `src`, `dest`, `weight`, `relationshipType` | Computes the Minimum Spanning Forest of the graph. See [MSF Algorithm](/algorithms/msf) for details. | diff --git a/index.md b/index.md index fbe9aba1..0ecd7dcf 100644 --- a/index.md +++ b/index.md @@ -30,7 +30,7 @@ FalkorDB delivers an **accurate, multi-tenant RAG solution powered by a low-late * Adopts the [Property Graph Model](https://github.com/opencypher/openCypher/blob/master/docs/property-graph-model.adoc) * Supports [OpenCypher](http://www.opencypher.org/) query language with proprietary extensions -* Offers [Full-Text Search](/cypher/indexing#full-text-indexing), [Vector Similarity](/cypher/indexing#vector-indexing), and [Range indexing](/cypher/indexing) for efficient querying +* Offers [Full-Text Search](/cypher/indexing/fulltext-index), [Vector Similarity](/cypher/indexing/vector-index), and [Range indexing](/cypher/indexing/range-index) for efficient querying * Supports both [RESP](https://redis.io/docs/reference/protocol-spec/) and [Bolt](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) protocols for flexible connectivity * Uses sparse adjacency matrix representation for efficient graph storage * Provides GraphRAG capabilities through the [GraphRAG SDK](/genai-tools/graphrag-sdk) for advanced graph reasoning and generative AI tasks From 60d6ceaefad58af8edfa0ab19781daded4a60042 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Wed, 19 Nov 2025 20:10:51 +0200 Subject: [PATCH 026/107] Fix formatting in vector-index.md for product creation (#288) --- cypher/indexing/vector-index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypher/indexing/vector-index.md b/cypher/indexing/vector-index.md index b2788ff1..102e61f0 100644 --- a/cypher/indexing/vector-index.md +++ b/cypher/indexing/vector-index.md @@ -351,7 +351,7 @@ graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimen # Insert products with embeddings (embeddings would come from your model) embedding = model.encode("laptop computer") # Your embedding model -graph.query(f"CREATE (p:Product {{name: 'Laptop', embedding: vecf32({embedding.tolist()})}})") +graph.query(f"CREATE (p:Product {name: 'Laptop', embedding: vecf32({embedding.tolist()})})") # Search for similar products query_embedding = model.encode("notebook pc") From d96d0f76029bdcbc2baa1bbc536b967b9f45a552 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Wed, 19 Nov 2025 20:12:51 +0200 Subject: [PATCH 027/107] Update vector-index.md (#289) --- cypher/indexing/vector-index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypher/indexing/vector-index.md b/cypher/indexing/vector-index.md index 102e61f0..e11784cc 100644 --- a/cypher/indexing/vector-index.md +++ b/cypher/indexing/vector-index.md @@ -398,7 +398,7 @@ graph.query("CREATE VECTOR INDEX FOR (p:Product) ON (p.embedding) OPTIONS {dimen // Insert products with embeddings (embeddings would come from your model) let embedding = model.encode("laptop computer"); // Your embedding model -graph.query(&format!("CREATE (p:Product {{name: 'Laptop', embedding: vecf32({:?})}})", embedding)).execute().await?; +graph.query(&format!("CREATE (p:Product {name: 'Laptop', embedding: vecf32({:?})})", embedding)).execute().await?; // Search for similar products let query_embedding = model.encode("notebook pc"); From ff5065d315dc6a91a385d4b1ff234fc50cb349d0 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:25:39 +0200 Subject: [PATCH 028/107] Add pricing plans comparison for FalkorDB --- cloud/free-tier.md | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/cloud/free-tier.md b/cloud/free-tier.md index 9f09afde..2de4ff8d 100644 --- a/cloud/free-tier.md +++ b/cloud/free-tier.md @@ -12,24 +12,26 @@ FalkorDB's free cloud tier gives you instant access to a graph database with mul The free tier provides everything you need to explore FalkorDB and build initial prototypes. When your application grows and requires TLS security, VPC networking, high availability, automated backups, or dedicated support, you can upgrade to a paid plan that includes these enterprise features. - - -| Feature | Included | -|---------|----------| -| [Multi-Graph / Multi-Tenancy](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/features.md#multi-tenancy) | ✓ | -| Community Support | ✓ | -| Cloud Providers (AWS, GCP) | ✓ | -| Storage (100MB) | ✓ | -| TLS | ✗ | -| VPC | ✗ | -| Cluster Deployment | ✗ | -| High Availability | ✗ | -| Multi-zone Deployment | ✗ | -| Scalability | ✗ | -| Continuous Persistence | ✗ | -| Automated Backups | ✗ | -| Advanced Monitoring | ✗ | -| Dedicated Account Manager | ✗ | +## FalkorDB Pricing Plans Comparison + +| Feature | FREE | STARTUP | PRO | ENTERPRISE | +| :--- | :---: | :---: | :---: | :---: | +| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** | +| Multi-Graph / Multi-Tenancy | **✓** | **✓** | **✓** | **✓** | +| Graph Access Control | **✓** | **✓** | **✓** | **✓** | +| TLS | ✗ | **✓** | **✓** | **✓** | +| VPC | ✗ | ✗ | ✗ | **✓** | +| Cluster Deployment | ✗ | ✗ | **✓** | **✓** | +| High Availability | ✗ | ✗ | **✓** | **✓** | +| Multi-zone Deployment | ✗ | ✗ | **✓** | **✓** | +| Scalability | ✗ | ✗ | **✓** | **✓** | +| Continuous Persistence | ✗ | ✗ | **✓** | **✓** | +| Automated Backups | ✗ | Every 12 Hours | Every 12 Hours | Every Hour | +| Advanced Monitoring | ✗ | ✗ | ✗ | **✓** | +| **Support** | Community | Community | 24/7 | Dedicated | +| Dedicated Account Manager | ✗ | ✗ | ✗ | **✓** | +| **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | AWS, GCP, Azure | AWS, GCP, Azure | +| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | #### Terms > ⚠️ Free instances that aren't utilized for 1 day will be stopped, and deleted after 7 days. From 8d1600c430c8e4614719cc794256e42a15d06290 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 12:00:28 +0200 Subject: [PATCH 029/107] Add macOS OpenMP library requirement to falkordblite.md (#291) * Extend falkordblite.md with Mac support details --- .wordlist.txt | 5 +++++ operations/falkordblite.md | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.wordlist.txt b/.wordlist.txt index 7318dd06..930132b8 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -691,3 +691,8 @@ pc queryEmbedding printf Jngle +Homebrew +libomp +sdist +dylib +xcode diff --git a/operations/falkordblite.md b/operations/falkordblite.md index 00f1c26e..0a8f594d 100644 --- a/operations/falkordblite.md +++ b/operations/falkordblite.md @@ -56,7 +56,15 @@ yum install python3-devel gcc make #### macOS -Install XCode command line utilities: +FalkorDBLite for macOS comes as a wheel package by default that can be installed using current versions of pip. + +**Important:** The FalkorDB module requires the OpenMP runtime library (`libomp`). If you encounter an error like `Library not loaded: /opt/homebrew/opt/libomp/lib/libomp.dylib`, install it using Homebrew: + +```bash +brew install libomp +``` + +To install FalkorDBLite on macOS using the sdist package instead, you will need the XCode command line utilities installed. If you do not have xcode installed on recent macOS releases, they can be installed by running: ```bash xcode-select --install From e09bf2f8197d3e923a70afc54ce6b6e299f888ac Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:01:38 +0200 Subject: [PATCH 030/107] Remove build/development content from falkordblite docs (#293) * Remove development-focused content from falkordblite docs --- operations/falkordblite.md | 42 +++----------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/operations/falkordblite.md b/operations/falkordblite.md index 0a8f594d..11df1f5b 100644 --- a/operations/falkordblite.md +++ b/operations/falkordblite.md @@ -5,12 +5,10 @@ parent: Operations description: "Self-contained Python interface to FalkorDB" --- -# [EXPERIMENTAL] FalkorDBLite +# FalkorDBLite FalkorDBLite is a self-contained Python interface to the FalkorDB graph database. It provides an embedded Redis server with the FalkorDB module that is automatically installed, configured, and managed when the bindings are used. -> **Note:** FalkorDBLite is an experimental feature. While it's functional and useful for development and testing, it's recommended to use a full FalkorDB deployment for production environments. - ## Key Features - **Easy to Use** - Built-in Redis server with FalkorDB module that is automatically installed, configured, and managed @@ -23,7 +21,6 @@ FalkorDBLite is a self-contained Python interface to the FalkorDB graph database ## Requirements - Python 3.12 or higher -- System build tools (automatically handled during installation on most systems) ## Installation @@ -36,48 +33,15 @@ pip install falkordblite The package will automatically install its dependencies, including: - `redis>=4.5` - Redis Python client - `psutil` - Process and system utilities -- `setuptools>38.0` - Build system - -### System Prerequisites - -#### Linux -On Ubuntu/Debian systems: - -```bash -apt-get install python3-dev build-essential -``` +### macOS Runtime Requirement -On Redhat/Fedora systems: - -```bash -yum install python3-devel gcc make -``` - -#### macOS - -FalkorDBLite for macOS comes as a wheel package by default that can be installed using current versions of pip. - -**Important:** The FalkorDB module requires the OpenMP runtime library (`libomp`). If you encounter an error like `Library not loaded: /opt/homebrew/opt/libomp/lib/libomp.dylib`, install it using Homebrew: +**Important:** On macOS, the FalkorDB module requires the OpenMP runtime library (`libomp`). If you encounter an error like `Library not loaded: /opt/homebrew/opt/libomp/lib/libomp.dylib`, install it using Homebrew: ```bash brew install libomp ``` -To install FalkorDBLite on macOS using the sdist package instead, you will need the XCode command line utilities installed. If you do not have xcode installed on recent macOS releases, they can be installed by running: - -```bash -xcode-select --install -``` - -#### Windows - -FalkorDBLite can be installed on Windows 10 and later under the Windows Subsystem for Linux (WSL). Follow the [WSL installation guide](https://learn.microsoft.com/en-us/windows/wsl/install) and then install the python-dev package: - -```bash -apt-get install python-dev -``` - ## Getting Started FalkorDBLite provides two main interfaces: From 0e7de2169078a75fd7fb3a86e91801f7fbbc6b74 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:19:05 +0200 Subject: [PATCH 031/107] update rest docs --- .wordlist.txt | 17 ---- integration/rest.md | 194 +++++++++++++++++++------------------------- 2 files changed, 84 insertions(+), 127 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 873edb35..33018d77 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -134,7 +134,6 @@ acos acyclic algo alister -alister allShortestPaths arccosine arcsine @@ -198,7 +197,6 @@ Jupyter javadocs javascript jedis -jfalkordb jinja jl jpbourbon @@ -324,7 +322,6 @@ vec euclideanDistance cosineDistance vecf - Dani Dovizioso Pedrosa @@ -335,7 +332,6 @@ RDB scalable scalability falkorDB - GraphName api auth @@ -369,9 +365,7 @@ FalkorConnectionInfo h1 tokio async -falkor fn - xxHash proc utf @@ -382,7 +376,6 @@ thpool sds CRoaring RSALv - hostnames bigmac calmcode @@ -391,15 +384,12 @@ kafka readme github pre -html -body table Explainer propname propvalue ro GenAI - Kruskal's MSF MST @@ -409,7 +399,6 @@ SPpath SSpath WCC WSL - undirected preprocessing subgraphs @@ -424,7 +413,6 @@ prev componentId Betweenness betweenness - LLMs Groq ontologies @@ -460,7 +448,6 @@ embeddings Colab chatbots Cognee's - alice cypher createQuery @@ -483,7 +470,6 @@ copyGraph myproject mut readOnlyQuery - Dunder Mifflin scranton @@ -495,7 +481,6 @@ Munger queryRelationships similarityFunction FIELDTERMINATOR -backend md Opire hh @@ -618,7 +603,6 @@ findByAgeNotIn findByNameAndAgeGreaterThan findFirstByOrderByCreatedAtDesc findTop10ByOrderByAgeDesc -findByAgeGreaterThanEqual findTop5ByOrderByAgeDesc findFirstByOrderByAgeAsc deleteByAge @@ -656,7 +640,6 @@ OpsRequest ComponentDefinition ClusterDefinition PodMonitor -BGSAVE datafile quorum NLB diff --git a/integration/rest.md b/integration/rest.md index 994b9bf4..ac7f6315 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -25,18 +25,21 @@ To start using the FalkorDB Browser REST API, follow these simple steps: First, you need to authenticate to get a JWT token: ```bash -curl -X POST "http://your-falkordb-browser-url/api/auth/login" \ +curl -X POST "http://your-falkordb-browser-url/api/auth/tokens/credentials" \ -H "Content-Type: application/json" \ -d '{ "username": "default", - "password": "" + "password": "", + "host": "localhost", + "port": "6379", + "tls": "false" }' ``` This will return a JWT token that you'll use for all subsequent requests: ```json { - "message": "Authentication successful", + "message": "Token created successfully", "token": "" } ``` @@ -71,10 +74,10 @@ curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH% ## Table of Contents ### Authentication -- [User login - POST /api/auth/login](#user-login---post-apiauthlogin) -- [Revoke JWT token - POST /api/auth/revoke](#revoke-jwt-token---post-apiauthrevoke) +- [Generate JWT Token with Credentials - POST /api/auth/tokens/credentials](#generate-jwt-token-with-credentials---post-apiauthtokenscredentials) - [List JWT tokens - GET /api/auth/tokens](#list-jwt-tokens---get-apiauthtokens) -- [Get token metadata - GET /api/auth/token/{tokenId}](#get-token-metadata---get-apiauthtokentokenid) +- [Get token metadata - GET /api/auth/tokens/{tokenId}](#get-token-metadata---get-apiauthtokenstokenid) +- [Revoke token by ID - DELETE /api/auth/tokens/{tokenId}](#revoke-token-by-id---delete-apiauthtokenstokenid) ### Status - [Check FalkorDB connection status - GET /api/status](#check-falkordb-connection-status---get-apistatus) @@ -133,20 +136,20 @@ curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH% ## Authentication -All endpoints except `/api/auth/login` require authentication using a JWT bearer token in the Authorization header: +All endpoints except `/api/auth/tokens/credentials` require authentication using a JWT bearer token in the Authorization header: ```http Authorization: Bearer ``` -### **User login** - `POST /api/auth/login` +### **Generate JWT Token with Credentials** - `POST /api/auth/tokens/credentials` -Generate JWT Token (Login) - Authenticate user and generate a JWT Personal Access Token (PAT) for external API access. +Authenticate with direct credentials and generate a JWT Personal Access Token (PAT) for external API access, CLI tools, or programmatic access. This endpoint does NOT require an existing session. #### Request Body - Content-Type: `application/json` -- Required fields: `username`, `password` -- Optional fields: `name`, `expiresAt`, `ttlSeconds`, `host`, `port`, `tls`, `ca` +- Required fields: `username`, `host`, `port`, `tls` +- Optional fields: `password`, `name`, `expiresAt`, `ttlSeconds` Example request: ```json @@ -158,21 +161,19 @@ Example request: "ttlSeconds": 31622400, "host": "localhost", "port": "6379", - "tls": "false", - "ca": "" + "tls": "false" } ``` **Request Parameters:** - `username` (required): Username for database connection -- `password` (required): Password for database connection (leave empty for 'default' user) +- `password` (optional): Password for database connection. Can be omitted (or empty) only when using the `default` user on localhost; otherwise a non-empty password is required - `name` (optional): Token name - `expiresAt` (optional): Token expiration date in ISO 8601 format -- `ttlSeconds` (optional): Time-to-live in seconds (default: 31622400) -- `host` (optional): FalkorDB host (default: "localhost") -- `port` (optional): FalkorDB port (default: "6379") -- `tls` (optional): Enable TLS connection - "true" or "false" -- `ca` (optional): Base64-encoded CA certificate for TLS +- `ttlSeconds` (optional): Time-to-live in seconds (max: 31622400) +- `host` (required): FalkorDB host +- `port` (required): FalkorDB port +- `tls` (required): Enable TLS connection - "true" or "false" #### Responses @@ -182,12 +183,12 @@ Example request: ```json { - "message": "Authentication successful", + "message": "Token created successfully", "token": "" } ``` -- **400**: Bad request - Invalid JSON, expiration date in the past, or invalid TTL value +- **400**: Bad request - Invalid JSON, validation error, expiration date in the past, or invalid TTL value - Content-Type: `application/json` - Example response: @@ -213,98 +214,13 @@ Example request: ```json { - "message": "Server configuration error: NEXTAUTH_SECRET is not set" - } - ``` - -### **Revoke JWT token** - `POST /api/auth/revoke` - -Revoke a JWT token by marking it as inactive in FalkorDB. Once revoked, the token cannot be used for authentication. Admins can revoke any token, while regular users can only revoke their own tokens. - -**Note:** Provide either `token` or `token_id` (not both) - -#### Headers -- `Authorization: Bearer ` (required) - -#### Request Body - -- Content-Type: `application/json` -- Required field: Either `token` or `token_id` (not both) - -Example request (using token): -```json -{ - "token": "" -} -``` - -Example request (using token_id): -```json -{ - "token_id": "1761055513181-215c579b-c6e1-4f10-9b07-aacbf89cda21" -} -``` - -**Request Parameters:** -- `token` (optional): JWT token to revoke -- `token_id` (optional): Token ID to revoke - -#### Responses - -- **200**: Token revoked successfully - - Content-Type: `application/json` - - Example response: - - ```json - { - "message": "Token revoked successfully", - "tokenId": "user-123-1640995200" - } - ``` - -- **400**: Bad request - missing token in request body - - Content-Type: `application/json` - - Example response: - - ```json - { - "message": "Token to revoke is required in request body" - } - ``` - -- **401**: Authentication failed - invalid or missing token - - Content-Type: `application/json` - - Example response: - - ```json - { - "message": "Authorization header with Bearer token required" - } - ``` - -- **403**: Forbidden - You can only revoke your own tokens (unless you are an Admin) - - Content-Type: `application/json` - - Example response: - - ```json - { - "message": "Forbidden: You can only revoke your own tokens" - } - ``` - -- **500**: Server configuration error - - Content-Type: `application/json` - - Example response: - - ```json - { - "message": "Server configuration error" + "message": "Server configuration error: NEXTAUTH_SECRET not set" } ``` ### **List JWT tokens** - `GET /api/auth/tokens` -Get a list of active JWT tokens. Admins can see all tokens from all users, while regular users can only see their own tokens. +Get a list of active JWT tokens. Admins see all tokens, regular users see only their own tokens. #### Headers - `Authorization: Bearer ` (required) @@ -336,9 +252,9 @@ Get a list of active JWT tokens. Admins can see all tokens from all users, while - **401**: Authentication failed - invalid or missing token - **500**: Internal server error -### **Get token metadata** - `GET /api/auth/token/{tokenId}` +### **Get token metadata** - `GET /api/auth/tokens/{tokenId}` -Get detailed metadata for a specific JWT token by its token ID. Admins can view any token, while regular users can only view their own tokens. +Get detailed metadata for a specific JWT token by its token ID. Admins can view any token, regular users can only view their own tokens. #### Headers - `Authorization: Bearer ` (required) @@ -391,6 +307,64 @@ Get detailed metadata for a specific JWT token by its token ID. Admins can view - **500**: Internal server error +### **Revoke token by ID** - `DELETE /api/auth/tokens/{tokenId}` + +Revoke a specific JWT token by its token ID. Once revoked, the token cannot be used for authentication. Admins can revoke any token, regular users can only revoke their own tokens. + +#### Headers +- `Authorization: Bearer ` (required) + +#### Parameters +- `tokenId` (path, required): Token ID to revoke + - Example: `1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81` + +#### Responses + +- **200**: Token revoked successfully + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token revoked successfully", + "tokenId": "1761053108078-554350d7-c965-4ed7-8d32-679b7f705e81" + } + ``` + +- **400**: Bad request - Token is already revoked + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token is already revoked" + } + ``` + +- **401**: Authentication failed - invalid or missing token + +- **403**: Forbidden - You can only revoke your own tokens (unless you are an Admin) + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Forbidden: You can only revoke your own tokens" + } + ``` + +- **404**: Token not found + - Content-Type: `application/json` + - Example response: + + ```json + { + "message": "Token not found" + } + ``` + +- **500**: Internal server error + --- ## Status From 2c44ec9ef96a7ecd5d965896c80d01924fd236da Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:21:15 +0200 Subject: [PATCH 032/107] Add official clients link to experimental BOLT documentation (#296) * Initial plan * Add link to official clients page in BOLT documentation Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- integration/bolt-support.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration/bolt-support.md b/integration/bolt-support.md index 5eafdc3a..998a36b0 100644 --- a/integration/bolt-support.md +++ b/integration/bolt-support.md @@ -12,6 +12,8 @@ redirect_from: # [EXPERIMENTAL] BOLT protocol support for FalkorDB +> **Note:** For production use cases, please use our [official client libraries](../getting-started/clients.md) instead. + FalkorDB provides an experimental support for querying using BOLT drivers. We intend to extend the support in the future versions, the current version is not meant to be used in production. This guide will walk you through the process of connecting to FalkorDB using the [BOLT protocol](https://en.wikipedia.org/wiki/Bolt_(network_protocol)) From 3ab241650b739a3f237940848ba8c0c59481a6ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:07:44 +0000 Subject: [PATCH 033/107] Initial plan From 7d57744353f3922661d86d0f5a49778b5045fe17 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:12:30 +0000 Subject: [PATCH 034/107] Add JavaScript/TypeScript integration section to LangChain docs Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- genai-tools/langchain.md | 126 +++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 11 deletions(-) diff --git a/genai-tools/langchain.md b/genai-tools/langchain.md index 14a90816..87172d4b 100644 --- a/genai-tools/langchain.md +++ b/genai-tools/langchain.md @@ -9,12 +9,20 @@ parent: "GenAI Tools" FalkorDB is integrated with [LangChain](https://www.langchain.com/), bringing powerful graph database capabilities to AI-driven applications. This integration enables the creation of AI agents with memory, enhancing their ability to retain state and context across interactions. +The FalkorDB LangChain integration is available for both **Python** and **JavaScript/TypeScript** environments, making it easy to build intelligent applications in your preferred language. + ## Resources -- 🔗 [FalkorDBQAChain Documentation](https://python.langchain.com/docs/use_cases/more/graph/graph_falkordb_qa) +- 🔗 [FalkorDBQAChain Documentation (Python)](https://python.langchain.com/docs/use_cases/more/graph/graph_falkordb_qa) +- 📦 [@falkordb/langchain-ts Package (JavaScript/TypeScript)](https://www.npmjs.com/package/@falkordb/langchain-ts) +- 💻 [FalkorDB-Langchain-js Repository](https://github.com/FalkorDB/FalkorDB-Langchain-js) - 📓 [Blog: Build AI Agents with Memory – LangChain + FalkorDB](https://www.falkordb.com/blog/building-ai-agents-with-memory-langchain/) -## Installation +--- + +## Python Integration + +### Installation Install LangChain with FalkorDB support: @@ -22,9 +30,9 @@ Install LangChain with FalkorDB support: pip install langchain langchain-community falkordb ``` -## Quick Start +### Quick Start -### 1. Connect to FalkorDB +#### 1. Connect to FalkorDB ```python from langchain_community.graphs import FalkorDBGraph @@ -39,7 +47,7 @@ graph = FalkorDBGraph( ) ``` -### 2. Create a Knowledge Graph from Text +#### 2. Create a Knowledge Graph from Text ```python from langchain.chains import GraphCypherQAChain @@ -56,7 +64,7 @@ chain = GraphCypherQAChain.from_llm( ) ``` -### 3. Query the Graph +#### 3. Query the Graph ```python # Ask natural language questions @@ -68,9 +76,9 @@ response = chain.run("What other movies did they act in?") print(response) ``` -## Advanced Usage +### Advanced Usage -### Using Graph Memory for Conversational AI +#### Using Graph Memory for Conversational AI ```python from langchain.memory import ConversationGraphMemory @@ -96,7 +104,7 @@ conversation.predict(input="I work as a software engineer") conversation.predict(input="What do you know about me?") ``` -### Custom Cypher Generation +#### Custom Cypher Generation ```python from langchain.chains.graph_qa.cypher import GraphCypherQAChain @@ -131,7 +139,7 @@ chain = GraphCypherQAChain.from_llm( response = chain.run("Find all products in the electronics category") ``` -### Loading Data into the Graph +#### Loading Data into the Graph ```python from langchain_community.document_loaders import TextLoader @@ -156,7 +164,7 @@ vector_store = FalkorDBVector.from_documents( ) ``` -### Graph RAG Pattern +#### Graph RAG Pattern ```python from langchain.chains import RetrievalQA @@ -183,6 +191,102 @@ response = qa_chain.run("What are the key features of our product?") print(response) ``` +--- + +## JavaScript/TypeScript Integration + +FalkorDB also provides a JavaScript/TypeScript integration for LangChain applications through the [@falkordb/langchain-ts](https://www.npmjs.com/package/@falkordb/langchain-ts) package. + +### Installation + +```bash +npm install @falkordb/langchain-ts falkordb +npm install langchain @langchain/openai +``` + +### Quick Start (JS/TS) + +```typescript +import { FalkorDBGraph } from "@falkordb/langchain-ts"; +import { ChatOpenAI } from "@langchain/openai"; +import { GraphCypherQAChain } from "@langchain/community/chains/graph_qa/cypher"; + +// Initialize FalkorDB connection +const graph = await FalkorDBGraph.initialize({ + host: "localhost", + port: 6379, + graph: "movies" +}); + +// Set up the language model +const model = new ChatOpenAI({ temperature: 0 }); + +// Create and populate the graph +await graph.query( + "CREATE (a:Actor {name:'Bruce Willis'})" + + "-[:ACTED_IN]->(:Movie {title: 'Pulp Fiction'})" +); + +// Refresh the graph schema +await graph.refreshSchema(); + +// Create a graph QA chain +const chain = GraphCypherQAChain.fromLLM({ + llm: model, + graph: graph as any, +}); + +// Ask questions about your graph +const response = await chain.run("Who played in Pulp Fiction?"); +console.log(response); +// Output: Bruce Willis played in Pulp Fiction. + +await graph.close(); +``` + +### Key Features (JS/TS) + +- **Natural Language Querying**: Convert questions to Cypher queries automatically +- **Schema Management**: Automatic schema refresh and retrieval +- **Type Safety**: Full TypeScript support with type definitions +- **Promise-based API**: Modern async/await patterns + +### API Reference (JS/TS) + +#### `FalkorDBGraph.initialize(config)` + +Create and initialize a new FalkorDB connection. + +**Config Options:** +- `host` (string): Database host (default: "localhost") +- `port` (number): Database port (default: 6379) +- `graph` (string): Graph name to use +- `url` (string): Alternative connection URL format +- `enhancedSchema` (boolean): Enable enhanced schema details + +#### `query(query: string)` + +Execute a Cypher query on the graph. + +```typescript +const result = await graph.query( + "MATCH (n:Person) RETURN n.name LIMIT 10" +); +``` + +#### `refreshSchema()` + +Update the graph schema information. + +```typescript +await graph.refreshSchema(); +console.log(graph.getSchema()); +``` + +For more detailed JavaScript/TypeScript examples and documentation, see the [LangChain JS/TS Integration Guide](/integration/langchain-js.html) and the [@falkordb/langchain-ts repository](https://github.com/FalkorDB/FalkorDB-Langchain-js). + +--- + ## Use Cases - **Conversational AI with Memory**: Build chatbots that remember user context across sessions From a16e2ff897a7b721ffd074b548fa0f84da64f78e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:14:12 +0000 Subject: [PATCH 035/107] Add cross-references and update index pages for LangChain JS/TS integration Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- genai-tools/index.md | 2 +- integration/index.md | 1 + integration/langchain-js.md | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/genai-tools/index.md b/genai-tools/index.md index 86220065..19e0953c 100644 --- a/genai-tools/index.md +++ b/genai-tools/index.md @@ -20,7 +20,7 @@ FalkorDB provides powerful tools and integrations for building intelligent GenAI - [GraphRAG-SDK](./graphrag-sdk.md): Build intelligent GraphRAG applications with FalkorDB and LLMs. - [AG2](./ag2.md): Build multi-agent AI systems with AG2 (formerly AutoGen) and FalkorDB GraphRAG. -- [LangChain](./langchain.md): Integration with LangChain for AI agents with memory. +- [LangChain](./langchain.md): Integration with LangChain for AI agents with memory (Python and JavaScript/TypeScript). - [LangGraph](./langgraph.md): Build stateful, multi-actor agentic applications with LangGraph. - [LlamaIndex](./llamaindex.md): Simplify development of LLM-powered applications with LlamaIndex. - [GraphRAG Toolkit](./graphrag-toolkit.md): AWS GraphRAG Toolkit integration for building knowledge graph applications. diff --git a/integration/index.md b/integration/index.md index d81ab4a5..546377ea 100644 --- a/integration/index.md +++ b/integration/index.md @@ -15,6 +15,7 @@ Learn how to leverage FalkorDB's flexible APIs and SDKs to build high-performanc ## Topics in This Section - [REST API](./rest.md): Learn how to interact with FalkorDB using its REST API for seamless integration with your applications. +- [LangChain JS/TS](./langchain-js.md): Integrate FalkorDB with LangChain JavaScript/TypeScript applications for AI-powered graph querying. - [Kafka Connect](./kafka-connect.md): Learn how to interact with FalkorDB using Kafka Connect sink to replicate data from third-party applications. - [Apache Jena](./jena.md): Learn how to use FalkorDB with Apache Jena via the jena-falkordb-adapter. - [BOLT protocol support](./bolt-support.md): Learn how to connect to FalkorDB using the BOLT protocol. diff --git a/integration/langchain-js.md b/integration/langchain-js.md index 80a606ab..873bfca8 100644 --- a/integration/langchain-js.md +++ b/integration/langchain-js.md @@ -11,6 +11,8 @@ parent: "Integration" The [@falkordb/langchain-ts](https://www.npmjs.com/package/@falkordb/langchain-ts) package enables developers to integrate FalkorDB with LangChain applications. The integration allows applications to accept natural language questions, generate Cypher queries automatically, retrieve relevant context from the graph database, and return responses in natural language. +> **Note:** FalkorDB also provides a Python integration for LangChain. See the [LangChain Python Integration](/genai-tools/langchain.html) for Python-specific documentation. + ## Installation ### Step 1 From ab2a49168342ddb0caf039f3389a816a20004c6c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 30 Nov 2025 08:15:26 +0000 Subject: [PATCH 036/107] Simplify installation command in JS/TS integration section Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- genai-tools/langchain.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/genai-tools/langchain.md b/genai-tools/langchain.md index 87172d4b..af69930b 100644 --- a/genai-tools/langchain.md +++ b/genai-tools/langchain.md @@ -200,8 +200,7 @@ FalkorDB also provides a JavaScript/TypeScript integration for LangChain applica ### Installation ```bash -npm install @falkordb/langchain-ts falkordb -npm install langchain @langchain/openai +npm install @falkordb/langchain-ts falkordb langchain @langchain/openai ``` ### Quick Start (JS/TS) From 122b84255b380fa948c514573fb33f00eb0512df Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:34:13 +0200 Subject: [PATCH 037/107] Update cloud/index.md with images and links Added images and links to enhance the documentation. --- cloud/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cloud/index.md b/cloud/index.md index 73a6fe01..bd0f6c67 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -5,6 +5,8 @@ nav_order: has_children: true --- +![FalkorDB Cloud Banner](https://github.com/user-attachments/assets/e436f01d-d60a-42cf-ac76-7e457180482e) + # FalkorDB Cloud DBaaS Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready. @@ -28,10 +30,14 @@ Get started with FalkorDB's cloud offering. The platform provides several enterp > *Azure: Bring-Your-Own-Cloud +![FalkorDB GitHub Repo - Video - 640x365](https://github.com/user-attachments/assets/fc9c1e74-1766-4842-bd5e-7570b39dea53) + ## Free Tier The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) + ## Startup Tier The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. From 1ca89d34d123e2e19f0c7ee439f2d1b58071b210 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:46:11 +0200 Subject: [PATCH 038/107] Revise features section and add demo link Reorganized features into a table format for clarity and added a demo link. --- cloud/index.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/cloud/index.md b/cloud/index.md index bd0f6c67..7072c4f7 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -11,24 +11,20 @@ has_children: true Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready. +> "FalkorDB has been a **game-changer** for our startup. Disappointed by Neo4j’s lack of support and slow performance, we turned to FalkorDB as a robust backend solution. Our wish? To run non-traversal queries with performance rivaling MongoDB or Postgres—something FalkorDB delivers where Neo4j fell short." +> +> — **Anthony Ray, 2Arrows CTO** +>
⭐️⭐️⭐️⭐️⭐️ + ## Features & Services -- Multi-Graph / Multi-Tenancy -- Graph Access Control -- TLS -- Automated Backups -- VPC Peering -- Dedicated Cluster Deployment -- High Availability -- Multi-zone Deployment -- Scalability -- Continuous Persistence -- Dedicated Support -- Advanced Monitoring -- Dedicated Account Manager -- ☁️ Cloud Providers: AWS, GCP - -> *Azure: Bring-Your-Own-Cloud +| Group | Features | +| :--- | :--- | +| **Availability & Resilience** | - High Availability
- Multi-zone Deployment
- Multi-Graph / Multi-Tenancy
- Automated Backups
- Continuous Persistence | +| **Security & Access** | - Graph Access Control
- TLS
- VPC Peering | +| **Deployment & Scaling** | - Dedicated Cluster Deployment
- Scalability | +| **Support & Monitoring** | - Dedicated Support
- Advanced Monitoring
- Dedicated Account Manager | +| ☁️ **Cloud Providers** | - AWS
- GCP
- Azure: Bring-Your-Own-Cloud | ![FalkorDB GitHub Repo - Video - 640x365](https://github.com/user-attachments/assets/fc9c1e74-1766-4842-bd5e-7570b39dea53) @@ -36,7 +32,9 @@ Get started with FalkorDB's cloud offering. The platform provides several enterp The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. -[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) +[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=z0XO4pb2t5Y) + ## Startup Tier From ba3ba8283b6e2249aa4abcc9ecd25f140a516e57 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:51:47 +0200 Subject: [PATCH 039/107] Revise video guide with image and sign-up link Updated video guide section with a new image and sign-up badge. --- cloud/free-tier.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cloud/free-tier.md b/cloud/free-tier.md index 2de4ff8d..1dbbae26 100644 --- a/cloud/free-tier.md +++ b/cloud/free-tier.md @@ -38,8 +38,8 @@ The free tier provides everything you need to explore FalkorDB and build initial Need an extension? Speak to [sales](https://www.falkordb.com/get-a-demo/)) ## Getting Started -### Video Guide -FalkorDB Graph DBaaS Free Tier Tutorial Video -> ▶️ Watch: https://www.youtube.com/watch?v=z0XO4pb2t5Y
-> ⚙️ Spin up your first FalkorDB Cloud instance: [Sign up](https://app.falkordb.cloud/signup) +[![FalkorDB Graph DBaaS Free Tier Tutorial Video](https://github.com/user-attachments/assets/56255f72-ff9d-4863-9942-b839257a723c)](https://www.youtube.com/watch?v=z0XO4pb2t5Y) + +⚙️ Spin up your first FalkorDB Cloud instance: +[![Sign Up](https://img.shields.io/badge/Sign%20Up-8A2BE2?style=for-the-badge)](https://app.falkordb.cloud/signup) From c3548bd138f20b3af09ff466e6e4ad980136dc6a Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:04:59 +0200 Subject: [PATCH 040/107] Create Startup Tier documentation in markdown Added detailed information about the Startup Tier, including pricing, features, and getting started instructions. --- cloud/startup-tier.md | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 cloud/startup-tier.md diff --git a/cloud/startup-tier.md b/cloud/startup-tier.md new file mode 100644 index 00000000..c0055658 --- /dev/null +++ b/cloud/startup-tier.md @@ -0,0 +1,59 @@ +--- +title: "Startup Tier" +parent: "Cloud DBaaS" +nav_order: 2 +description: "FalkorDB DBaaS Startup Tier" +--- + +![FalkorDB Cloud Startup Tier Banner](https://github.com/user-attachments/assets/a60eacb7-2af6-432e-84c8-7c3dbe98422c) + + +# Startup Tier +FalkorDB's **Startup Tier** gives you instant access to a production-ready graph database starting at **$73/Month**. This tier is designed to help you **Build a Powerful MVP** with standalone deployment, multi-graph support, and multi-tenancy capabilities. You can deploy on AWS, GCP, or Azure (BYOC) and rely on community support to grow your application. + +The Startup Tier includes essential features like **TLS** and **Automated Backups (Every 12 Hours)**, making it a robust, secure choice for your first production workload. When your application requires High Availability, dedicated support, or advanced enterprise features like VPC networking, you can easily upgrade to a Pro or Enterprise plan. + +## FalkorDB Pricing Plans Comparison + +| Feature | FREE | STARTUP | PRO | ENTERPRISE | +| :--- | :---: | :---: | :---: | :---: | +| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** | +| Multi-Graph / Multi-Tenancy | ✓ | **🟢** | ✓ | ✓ | +| Graph Access Control | ✓ | **🟢** | ✓ | ✓ | +| **TLS** | ✗ | **🟢** | ✓ | ✓ | +| VPC | ✗ | **🔴** | ✗ | ✓ | +| Cluster Deployment | ✗ | **🔴** | ✓ | ✓ | +| High Availability | ✗ | **🔴** | ✓ | ✓ | +| Multi-zone Deployment | ✗ | **🔴** | ✓ | ✓ | +| Scalability | ✗ | **🔴** | ✓ | ✓ | +| Continuous Persistence | ✗ | **🔴** | ✓ | ✓ | +| **Automated Backups** | ✗ | **Every 12 Hours** | Every 12 Hours | Every Hour | +| Advanced Monitoring | ✗ | **🔴** | ✗ | ✓ | +| **Support** | Community | **Community** | 24/7 | Dedicated | +| Dedicated Account Manager | ✗ | **🔴** | ✗ | ✓ | +| **Cloud Providers** | AWS, GCP, Azure | **AWS, GCP, Azure** | AWS, GCP, Azure | AWS, GCP, Azure | +| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | + +## Terms +### Pricing Calculation +> We calculate deployment costs based on **Memory GB/Hour** usage. Each Memory GB/Hour costs **$0.100**. +> +> The list below shows approximate monthly costs for different instance sizes (based on 730 hours/month): +> +> * **1 Gigabyte memory instance:** $0.100 × 1 (Memory GB) × 730 hours = **$73/month*** +> * **2 Gigabyte memory instance:** $0.100 × 2 (Memory GB) × 730 hours = **$146/month*** +> +> You can estimate your monthly costs by multiplying your instance's memory allocation (in GB) by **$73**. +> +> Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost. +> +> ⚠️ Prices are subject to change + +## Getting Started + + + FalkorDB Graph DBaaS Startup Tier Tutorial Video + + +⚙️ Spin up your first FalkorDB Cloud instance: +[![Sign Up](https://img.shields.io/badge/Sign%20Up-8A2BE2?style=for-the-badge)](https://app.falkordb.cloud/signup) From d4056bb5a0c687e2643bba5c83996608fdd22456 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:12:35 +0200 Subject: [PATCH 041/107] Create Pro Tier documentation for FalkorDB Added detailed information about the Pro Tier of FalkorDB, including pricing, features, and comparison with other tiers. --- cloud/pro-tier.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 cloud/pro-tier.md diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md new file mode 100644 index 00000000..0c146f94 --- /dev/null +++ b/cloud/pro-tier.md @@ -0,0 +1,85 @@ +--- +title: "Pro Tier" +parent: "Cloud DBaaS" +nav_order: 3 +description: "FalkorDB DBaaS Pro Tier" +--- + +![FalkorDB Cloud Pro Tier Banner](https://github.com/user-attachments/assets/2d39df96-f932-4cba-a124-bfff93f9a0ca) + + +# Pro Tier +FalkorDB's **Pro Tier** is your solution for high-performance, production-ready graph database workloads, starting at **$350/Month**. This tier is designed for applications requiring **High Availability (HA)**, **Multi-zone Deployment**, and robust **Scalability**. It includes essential infrastructure features like **Cluster Deployment** and **Continuous Persistence (AOF + Snapshot)**, backed by **24-hour Dedicated Support**. + +The Pro Tier provides a robust environment to scale your application with confidence. When your needs extend to features like VPC Peering, Advanced Monitoring, or a Dedicated Account Manager, you can easily upgrade to the Enterprise plan. + +## FalkorDB Pricing Plans Comparison + +| Feature | FREE | STARTUP | PRO | ENTERPRISE | +| :--- | :---: | :---: | :---: | :---: | +| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** | +| Multi-Graph / Multi-Tenancy | ✓ | ✓ | **🟢** | ✓ | +| Graph Access Control | ✓ | ✓ | **🟢** | ✓ | +| **TLS** | ✗ | ✓ | **🟢** | ✓ | +| VPC | ✗ | ✗ | **🔴** | ✓ | +| Cluster Deployment | ✗ | ✗ | **🟢** | ✓ | +| High Availability | ✗ | ✗ | **🟢** | ✓ | +| Multi-zone Deployment | ✗ | ✗ | **🟢** | ✓ | +| Scalability | ✗ | ✗ | **🟢** | ✓ | +| Continuous Persistence | ✗ | ✗ | **🟢** | ✓ | +| **Automated Backups** | ✗ | Every 12 Hours | **Every 12 Hours** | Every Hour | +| Advanced Monitoring | ✗ | ✗ | **🔴** | ✓ | +| **Support** | Community | Community | **24/7** | Dedicated | +| Dedicated Account Manager | ✗ | ✗ | **🔴** | ✓ | +| **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | **AWS, GCP, Azure** | AWS, GCP, Azure | +| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | + +## Terms +### Pricing Calculation +> We charge deployments based on **Core/Hour** and **Memory GB/Hour** usage. You pay **$0.200 per Core/Hour** and **$0.01 per Memory GB/Hour**. +> +> ### Monthly Instance Pricing +> Here are the approximate monthly costs for different instance configurations (based on 730 hours/month): +> +> **E2-standard-2 / m6i.large (Starting Instance)** +> * 4 cores × $0.200 × 730 hours = $292.00 +> * 8GB memory × $0.01 × 730 hours = $58.40 +> * **Total monthly cost:** **$350.40** +> +> **E2-standard-4 / m6i.xlarge** +> * 4 cores × $0.200 × 730 hours = $584.00 +> * 16GB memory × $0.01 × 730 hours = $116.80 +> * **Total monthly cost:** **$700.80** +> +> **Larger Custom Instances** +> * **E2-custom-4-8192 / c6i.xlarge:** $642.40 +> * **E2-custom-8-16384 / c6i.2xlarge:** $1,284.80 +> * **E2-custom-16-32768 / c6i.4xlarge:** $2,569.60 +> * **E2-custom-32-65536 / c6i.8xlarge:** $5,139.20 +> +> ### Additional Deployment Components +> You must add these component costs to your base instance costs when using replication or cluster deployment configurations. +> +> **Replication Deployments** +> (Sentinel component: 2 vCPUs and 2GB memory) +> * Core cost: 2 cores × $0.200 × 730 hours = $292.00 +> * Memory cost: 2GB × $0.01 × 730 hours = $14.60 +> * **Additional monthly cost:** **$306.60** +> +> **Cluster Deployments** +> (Rebalancer component: 2 vCPUs and 2GB memory) +> * Core cost: 2 cores × $0.200 × 730 hours = $292.00 +> * Memory cost: 2GB × $0.01 × 730 hours = $14.60 +> * **Additional monthly cost:** **$306.60** +> +> Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost. +> ⚠️ Prices are subject to change + +## Getting Started + + + FalkorDB Graph DBaaS Pro Tier Tutorial Video + + +⚙️ Spin up your first FalkorDB Cloud instance: +[![Sign Up](https://img.shields.io/badge/Sign%20Up-8A2BE2?style=for-the-badge)](https://app.falkordb.cloud/signup) From b1f9a34c99df41384a162a3ebab255a066b0be11 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:16:43 +0200 Subject: [PATCH 042/107] Create documentation for FalkorDB Enterprise Tier Added detailed information about the FalkorDB Enterprise Tier, including pricing, features, and getting started instructions. --- cloud/enterprise-tier.md | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 cloud/enterprise-tier.md diff --git a/cloud/enterprise-tier.md b/cloud/enterprise-tier.md new file mode 100644 index 00000000..f877e7da --- /dev/null +++ b/cloud/enterprise-tier.md @@ -0,0 +1,53 @@ +--- +title: "Enterprise Tier" +parent: "Cloud DBaaS" +nav_order: 4 +description: "FalkorDB DBaaS Enterprise Tier" +--- + +![FalkorDB Cloud Enterprise Tier Banner](https://github.com/user-attachments/assets/f03bb001-1916-4e0f-9a82-cb8271309855) + + +# Enterprise Tier +FalkorDB's **Enterprise Tier** is designed for the most demanding workloads, offering ultimate performance, scale, and customization, with pricing determined on a **Custom** basis. This tier includes **every available enterprise feature**, such as **VPC Peering**, **Advanced Monitoring**, and **Dedicated Account Manager** support. + +The Enterprise Tier is fully optimized for mission-critical applications, providing the highest levels of security, availability, and dedicated operational support. Deployment configurations are tailored to your specific infrastructure, scale, and compliance requirements. + +## FalkorDB Pricing Plans Comparison + +| Feature | FREE | STARTUP | PRO | ENTERPRISE | +| :--- | :---: | :---: | :---: | :---: | +| **Monthly Cost (from)** | **Free** | **$73** | **$350** | **Custom** | +| Multi-Graph / Multi-Tenancy | ✓ | ✓ | ✓ | **🟢** | +| Graph Access Control | ✓ | ✓ | ✓ | **🟢** | +| **TLS** | ✗ | ✓ | ✓ | **🟢** | +| **VPC** | ✗ | ✗ | ✗ | **🟢** | +| Cluster Deployment | ✗ | ✗ | ✓ | **🟢** | +| High Availability | ✗ | ✗ | ✓ | **🟢** | +| Multi-zone Deployment | ✗ | ✗ | ✓ | **🟢** | +| Scalability | ✗ | ✗ | ✓ | **🟢** | +| Continuous Persistence | ✗ | ✗ | ✓ | **🟢** | +| **Automated Backups** | ✗ | Every 12 Hours | Every 12 Hours | **Every Hour** | +| **Advanced Monitoring** | ✗ | ✗ | ✗ | **🟢** | +| **Support** | Community | Community | 24/7 | **Dedicated** | +| **Dedicated Account Manager** | ✗ | ✗ | ✗ | **🟢** | +| **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | AWS, GCP, Azure | **AWS, GCP, Azure** | +| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | + +## Terms +### Consultation and Pricing +> The Enterprise Tier is customized to your specific needs, leveraging dedicated resources, tailored support SLAs, and private deployment options. Pricing is calculated based on the custom configuration of cores, memory, and additional enterprise components. +> +> **For precise pricing, deployment details, and a dedicated consultation:** +> **[Contact our Sales Team](LINK_TO_SALES_CONTACT_HERE)** +> +> ⚠️ Prices are subject to change + +## Getting Started + + + FalkorDB Graph DBaaS Enterprise Tier Tutorial Video + + +⚙️ To begin your Enterprise journey, schedule a consultation: +[![Contact Us](https://img.shields.io/badge/Contact%20Us-8A2BE2?style=for-the-badge)](mailto:info@falkordb.com) From 7b6da8e3ac45c46e70c88c4978165351eef2ddda Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:19:09 +0200 Subject: [PATCH 043/107] Disable schema endpoints for rest --- integration/rest.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration/rest.md b/integration/rest.md index ac7f6315..48e74685 100644 --- a/integration/rest.md +++ b/integration/rest.md @@ -106,7 +106,7 @@ curl -N -X GET "http://your-falkordb-browser-url/api/graph/my_graph?query=MATCH% - [Get specific configuration value - GET /api/graph/config/{config}](#get-specific-configuration-value---get-apigraphconfigconfig) - [Set configuration value - POST /api/graph/config/{config}](#set-configuration-value---post-apigraphconfigconfig) -### Schema Management + ### User Management - [List all users - GET /api/user](#list-all-users---get-apiuser) @@ -920,7 +920,7 @@ Set the value of a specific configuration parameter. --- -## Schema Management + --- From c40515b64e0b07ff3a7f7535a2f480d31d1b50c8 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:00:33 +0200 Subject: [PATCH 044/107] Revise call-to-action and fix markdown tables Updated call-to-action section and corrected markdown table alignment for instance pricing. --- cloud/pro-tier.md | 74 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md index 0c146f94..d9d178f6 100644 --- a/cloud/pro-tier.md +++ b/cloud/pro-tier.md @@ -32,46 +32,48 @@ The Pro Tier provides a robust environment to scale your application with confid | **Support** | Community | Community | **24/7** | Dedicated | | Dedicated Account Manager | ✗ | ✗ | **🔴** | ✓ | | **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | **AWS, GCP, Azure** | AWS, GCP, Azure | -| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | +| **Get started** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | ## Terms ### Pricing Calculation > We charge deployments based on **Core/Hour** and **Memory GB/Hour** usage. You pay **$0.200 per Core/Hour** and **$0.01 per Memory GB/Hour**. -> -> ### Monthly Instance Pricing -> Here are the approximate monthly costs for different instance configurations (based on 730 hours/month): -> -> **E2-standard-2 / m6i.large (Starting Instance)** -> * 4 cores × $0.200 × 730 hours = $292.00 -> * 8GB memory × $0.01 × 730 hours = $58.40 -> * **Total monthly cost:** **$350.40** -> -> **E2-standard-4 / m6i.xlarge** -> * 4 cores × $0.200 × 730 hours = $584.00 -> * 16GB memory × $0.01 × 730 hours = $116.80 -> * **Total monthly cost:** **$700.80** -> -> **Larger Custom Instances** -> * **E2-custom-4-8192 / c6i.xlarge:** $642.40 -> * **E2-custom-8-16384 / c6i.2xlarge:** $1,284.80 -> * **E2-custom-16-32768 / c6i.4xlarge:** $2,569.60 -> * **E2-custom-32-65536 / c6i.8xlarge:** $5,139.20 -> -> ### Additional Deployment Components -> You must add these component costs to your base instance costs when using replication or cluster deployment configurations. -> -> **Replication Deployments** -> (Sentinel component: 2 vCPUs and 2GB memory) -> * Core cost: 2 cores × $0.200 × 730 hours = $292.00 -> * Memory cost: 2GB × $0.01 × 730 hours = $14.60 -> * **Additional monthly cost:** **$306.60** -> -> **Cluster Deployments** -> (Rebalancer component: 2 vCPUs and 2GB memory) -> * Core cost: 2 cores × $0.200 × 730 hours = $292.00 -> * Memory cost: 2GB × $0.01 × 730 hours = $14.60 -> * **Additional monthly cost:** **$306.60** -> +I sincerely apologize for the confusion! You're right - I need to use the colon alignment syntax properly. Here are the correct markdown tables: + +## Standalone + +| Instance Type | Monthly Cost | +| :--- | ---: | +| E2-standard-2 / m6i.large (Starting Instance) | $350.40 | +| E2-standard-4 / m6i.xlarge | $700.80 | +| E2-custom-4-8192 / c6i.xlarge | $642.40 | +| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 | +| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | +| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | + +## Replicated (High Availability, Master-Replica) + +| Instance Type | Monthly Cost | +| :--- | ---: | +| E2-standard-2 / m6i.large (Starting Instance) | $350.40 | +| E2-standard-4 / m6i.xlarge | $700.80 | +| E2-custom-4-8192 / c6i.xlarge | $642.40 | +| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 | +| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | +| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | +| **Additional monthly cost** | **$306.60** | + +## Clustered (High Availability, Min. 3 Masters and 3 Replicas) + +| Instance Type | Monthly Cost | +| :--- | ---: | +| E2-standard-2 / m6i.large (Starting Instance) | $350.40 | +| E2-standard-4 / m6i.xlarge | $700.80 | +| E2-custom-4-8192 / c6i.xlarge | $642.40 | +| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 | +| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | +| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | +| **Additional monthly cost** | **$306.60** | + > Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost. > ⚠️ Prices are subject to change From ebdc31c86f5c87dcdd4006785a877cf851364f8e Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Wed, 10 Dec 2025 12:02:06 +0200 Subject: [PATCH 045/107] Update pro-tier.md --- cloud/pro-tier.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md index d9d178f6..1372a3f2 100644 --- a/cloud/pro-tier.md +++ b/cloud/pro-tier.md @@ -37,7 +37,6 @@ The Pro Tier provides a robust environment to scale your application with confid ## Terms ### Pricing Calculation > We charge deployments based on **Core/Hour** and **Memory GB/Hour** usage. You pay **$0.200 per Core/Hour** and **$0.01 per Memory GB/Hour**. -I sincerely apologize for the confusion! You're right - I need to use the colon alignment syntax properly. Here are the correct markdown tables: ## Standalone @@ -52,27 +51,28 @@ I sincerely apologize for the confusion! You're right - I need to use the colon ## Replicated (High Availability, Master-Replica) -| Instance Type | Monthly Cost | -| :--- | ---: | -| E2-standard-2 / m6i.large (Starting Instance) | $350.40 | -| E2-standard-4 / m6i.xlarge | $700.80 | -| E2-custom-4-8192 / c6i.xlarge | $642.40 | -| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 | -| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | -| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | -| **Additional monthly cost** | **$306.60** | + +| Instance Type | Monthly Cost | +| :-------------------------------------------- | -----------: | +| E2-standard-2 / m6i.large (Starting Instance) | \$1,007.40 | +| E2-standard-4 / m6i.xlarge | \$1,708.20 | +| E2-custom-4-8192 / c6i.xlarge | \$1,591.40 | +| E2-custom-8-16384 / c6i.2xlarge | \$2,876.20 | +| E2-custom-16-32768 / c6i.4xlarge | \$5,445.80 | +| E2-custom-32-65536 / c6i.8xlarge | \$10,585.00 | + ## Clustered (High Availability, Min. 3 Masters and 3 Replicas) -| Instance Type | Monthly Cost | -| :--- | ---: | -| E2-standard-2 / m6i.large (Starting Instance) | $350.40 | -| E2-standard-4 / m6i.xlarge | $700.80 | -| E2-custom-4-8192 / c6i.xlarge | $642.40 | -| E2-custom-8-16384 / c6i.2xlarge | $1,284.80 | -| E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | -| E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | -| **Additional monthly cost** | **$306.60** | +| Instance Type | Monthly Cost | +| :-------------------------------------------- | -----------: | +| E2-standard-2 / m6i.large (Starting Instance) | \$2,409.00 | +| E2-standard-4 / m6i.xlarge | \$4,511.40 | +| E2-custom-4-8192 / c6i.xlarge | \$4,161.00 | +| E2-custom-8-16384 / c6i.2xlarge | \$8,015.40 | +| E2-custom-16-32768 / c6i.4xlarge | \$15,724.20 | +| E2-custom-32-65536 / c6i.8xlarge | \$31,141.80 | + > Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost. > ⚠️ Prices are subject to change From 72c35b17ffd8ff912002aab3127666cddb1a75ab Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:30:55 +0200 Subject: [PATCH 046/107] Add billing and setup section to index.md Added billing setup instructions for FalkorDB cloud tiers. --- cloud/index.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cloud/index.md b/cloud/index.md index 7072c4f7..f448a0fb 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -35,15 +35,32 @@ The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes [![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) [![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=z0XO4pb2t5Y) +--- + +### Billing & Setup +ℹ️ Prior to subscribing to any of FalkorDB's paid cloud tiers, please set up your billing information here: +> Adding your billing information is an easy, 3-step process: +> 1. Create a billing account ([Link](https://app.falkordb.cloud/billing)) +> 2. Input your billing information [(Link)](https://billing.stripe.com/p/session/live_YWNjdF8xT3VGdlpBTEZxNUJKZk5kLF9UYUVZQ3A5WGpaZXp2Sk1CdVBTMUV5YWhqVUlXS3Vv01007QZVIlCR) +> 3. Create a new instance within your selected tier + +![FDB-cloud-billing-how-to](https://github.com/user-attachments/assets/d5d6ce47-0bbc-4c71-b5fa-60a43677fb3f) + ## Startup Tier The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/startup-tier.md) +[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=xjpLPoQgo2s) + ## Pro Tier The FalkorDB Pro Tier provides a production-ready FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/pro-tier.md) +[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://youtu.be/UIzrW9otvYM?si=P1too6QjZ5r9AHtB) + ## Enterprise Contact us From 96dd6d5d37d9fda7c41831a251efdefb00ebab81 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:14:49 +0200 Subject: [PATCH 047/107] Update headings and correct instance type labels --- cloud/pro-tier.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md index 1372a3f2..3b5e9912 100644 --- a/cloud/pro-tier.md +++ b/cloud/pro-tier.md @@ -49,10 +49,10 @@ The Pro Tier provides a robust environment to scale your application with confid | E2-custom-16-32768 / c6i.4xlarge | $2,569.60 | | E2-custom-32-65536 / c6i.8xlarge | $5,139.20 | -## Replicated (High Availability, Master-Replica) +## Replicated (High Availability, Master (x1), Replica (x1)) -| Instance Type | Monthly Cost | +| Instances Type | Monthly Cost | | :-------------------------------------------- | -----------: | | E2-standard-2 / m6i.large (Starting Instance) | \$1,007.40 | | E2-standard-4 / m6i.xlarge | \$1,708.20 | @@ -62,9 +62,9 @@ The Pro Tier provides a robust environment to scale your application with confid | E2-custom-32-65536 / c6i.8xlarge | \$10,585.00 | -## Clustered (High Availability, Min. 3 Masters and 3 Replicas) +## Clustered (High Availability, Masters (x3), and Replicas (x3)) -| Instance Type | Monthly Cost | +| Instances Type | Monthly Cost | | :-------------------------------------------- | -----------: | | E2-standard-2 / m6i.large (Starting Instance) | \$2,409.00 | | E2-standard-4 / m6i.xlarge | \$4,511.40 | From fb0fc67777aa4895cdc5a8b93393960343e23334 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:26:18 +0200 Subject: [PATCH 048/107] Comment out clustered instances pricing section Commented out the section on clustered instances and their costs. --- cloud/pro-tier.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md index 3b5e9912..376685a4 100644 --- a/cloud/pro-tier.md +++ b/cloud/pro-tier.md @@ -62,6 +62,7 @@ The Pro Tier provides a robust environment to scale your application with confid | E2-custom-32-65536 / c6i.8xlarge | \$10,585.00 | + > Use our **[graph size calculator](https://www.falkordb.com/graph-database-graph-size-calculator/)** to further estimate your cost. > ⚠️ Prices are subject to change From 91e5be22af07e991e658c14b2645341e1fcaf85f Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Fri, 12 Dec 2025 16:54:56 +0200 Subject: [PATCH 049/107] Add trendshift badge to index.md (#301) * Add trendshift badge to index.md Added badge for Trendshift * Add 'Trendshift' to the wordlist * Add Trendshift badge to README --- .wordlist.txt | 1 + README.md | 1 + index.md | 3 +++ 3 files changed, 5 insertions(+) diff --git a/.wordlist.txt b/.wordlist.txt index 1369fc11..dd4b8447 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -684,3 +684,4 @@ libomp sdist dylib xcode +Trendshift diff --git a/README.md b/README.md index 147897b9..3520354a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Discord](https://img.shields.io/discord/1146782921294884966?style=flat-square)](https://discord.gg/ErBEqN9E) [![Try Free](https://img.shields.io/badge/Try%20Free-FalkorDB%20Cloud-FF8101?labelColor=FDE900&style=flat-square)](https://app.falkordb.cloud) +[![Trendshift](https://trendshift.io/api/badge/repositories/14787)](https://trendshift.io/repositories/14787) # https://docs.falkordb.com diff --git a/index.md b/index.md index 0ecd7dcf..87f4a75c 100644 --- a/index.md +++ b/index.md @@ -5,6 +5,9 @@ nav_order: 1 description: "The fastest way to your knowledge" permalink: / --- + +[![Trendshift](https://trendshift.io/api/badge/repositories/14787)](https://trendshift.io/repositories/14787) + [![Docker Hub](https://img.shields.io/docker/pulls/falkordb/falkordb?label=Docker&style=flat-square)](https://hub.docker.com/r/falkordb/falkordb/) [![Discord](https://img.shields.io/discord/1146782921294884966?style=flat-square)](https://discord.gg/ErBEqN9E) [![Try Free](https://img.shields.io/badge/Try%20Free-FalkorDB%20Cloud-FF8101?labelColor=FDE900&style=flat-square)](https://app.falkordb.cloud) From b4cb17f5ae3147dbecb111682ca9d9d695939c21 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Sun, 14 Dec 2025 10:49:28 +0200 Subject: [PATCH 050/107] Change tutorial video thumbnail dimensions Updated the tutorial video thumbnail size for better display. --- cloud/pro-tier.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/pro-tier.md b/cloud/pro-tier.md index 376685a4..d9a1adf6 100644 --- a/cloud/pro-tier.md +++ b/cloud/pro-tier.md @@ -81,7 +81,7 @@ The Pro Tier provides a robust environment to scale your application with confid ## Getting Started - FalkorDB Graph DBaaS Pro Tier Tutorial Video + FalkorDB Graph DBaaS Pro Tier Tutorial Video ⚙️ Spin up your first FalkorDB Cloud instance: From f089dddcb64892fa4fd2c509b6269b25125c3172 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Sun, 14 Dec 2025 10:49:51 +0200 Subject: [PATCH 051/107] Change thumbnail size in startup-tier.md Updated video thumbnail size for better display. --- cloud/startup-tier.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/startup-tier.md b/cloud/startup-tier.md index c0055658..82a6e176 100644 --- a/cloud/startup-tier.md +++ b/cloud/startup-tier.md @@ -52,7 +52,7 @@ The Startup Tier includes essential features like **TLS** and **Automated Backup ## Getting Started - FalkorDB Graph DBaaS Startup Tier Tutorial Video + FalkorDB Graph DBaaS Startup Tier Tutorial Video ⚙️ Spin up your first FalkorDB Cloud instance: From cbd2328ce0957784209ad0fcf1ec80f47bf96bbc Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Sun, 14 Dec 2025 10:50:53 +0200 Subject: [PATCH 052/107] Modify Call-to-Action and image size in enterprise tier Updated the Call-to-Action link and adjusted the image size in the Getting Started section. --- cloud/enterprise-tier.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cloud/enterprise-tier.md b/cloud/enterprise-tier.md index f877e7da..87b57c0d 100644 --- a/cloud/enterprise-tier.md +++ b/cloud/enterprise-tier.md @@ -32,7 +32,6 @@ The Enterprise Tier is fully optimized for mission-critical applications, provid | **Support** | Community | Community | 24/7 | **Dedicated** | | **Dedicated Account Manager** | ✗ | ✗ | ✗ | **🟢** | | **Cloud Providers** | AWS, GCP, Azure | AWS, GCP, Azure | AWS, GCP, Azure | **AWS, GCP, Azure** | -| **Call-to-Action** | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Sign up](https://app.falkordb.cloud/signup) | [Contact Us](mailto:info@falkordb.com) | ## Terms ### Consultation and Pricing @@ -46,7 +45,7 @@ The Enterprise Tier is fully optimized for mission-critical applications, provid ## Getting Started - FalkorDB Graph DBaaS Enterprise Tier Tutorial Video + FalkorDB Graph DBaaS Enterprise Tier Tutorial Video ⚙️ To begin your Enterprise journey, schedule a consultation: From c8b98db73ee1ca66a7731858f555f065e59d694b Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:56:04 +0200 Subject: [PATCH 053/107] Update cloud index with Free Tier and feature changes Removed a customer testimonial and updated the cloud providers list. Added the Free Tier section earlier in the document and adjusted descriptions for the Startup and Pro Tiers. --- cloud/index.md | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/cloud/index.md b/cloud/index.md index f448a0fb..91d17fbb 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -11,11 +11,6 @@ has_children: true Get started with FalkorDB's cloud offering. The platform provides several enterprise features, including multi-tenancy, across all tiers. Browse the available plans and select the one that suits your needs. You can scale and upgrade your deployment when ready. -> "FalkorDB has been a **game-changer** for our startup. Disappointed by Neo4j’s lack of support and slow performance, we turned to FalkorDB as a robust backend solution. Our wish? To run non-traversal queries with performance rivaling MongoDB or Postgres—something FalkorDB delivers where Neo4j fell short." -> -> — **Anthony Ray, 2Arrows CTO** ->
⭐️⭐️⭐️⭐️⭐️ - ## Features & Services | Group | Features | @@ -24,16 +19,7 @@ Get started with FalkorDB's cloud offering. The platform provides several enterp | **Security & Access** | - Graph Access Control
- TLS
- VPC Peering | | **Deployment & Scaling** | - Dedicated Cluster Deployment
- Scalability | | **Support & Monitoring** | - Dedicated Support
- Advanced Monitoring
- Dedicated Account Manager | -| ☁️ **Cloud Providers** | - AWS
- GCP
- Azure: Bring-Your-Own-Cloud | - -![FalkorDB GitHub Repo - Video - 640x365](https://github.com/user-attachments/assets/fc9c1e74-1766-4842-bd5e-7570b39dea53) - -## Free Tier - -The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. - -[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) -[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=z0XO4pb2t5Y) +| ☁️ **Cloud Providers** | - AWS
- GCP
- Azure
- BYOC (AWS, GCP) | --- @@ -46,21 +32,30 @@ The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes ![FDB-cloud-billing-how-to](https://github.com/user-attachments/assets/d5d6ce47-0bbc-4c71-b5fa-60a43677fb3f) +## Free Tier + +The FalkorDB Free Tier provides a free FalkorDB instance for evaluation purposes. You can deploy, connect, and share the instance with minimal effort and no maintenance. + +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/free-tier.md) +[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=z0XO4pb2t5Y) ## Startup Tier -The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. +The FalkorDB Startup Tier provides a production-ready standalone FalkorDB deployment. Pick your machine size, add your dataset, and start extracting insights. [![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/startup-tier.md) [![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://www.youtube.com/watch?v=xjpLPoQgo2s) ## Pro Tier -The FalkorDB Pro Tier provides a production-ready FalkorDB deployment. Choose your deployment mode, connect, and share the instance with minimal effort and no maintenance. Pick your machine size, add your dataset, and start extracting insights. +The Pro Tier provides a robust, dedicated environment to scale your application, including highly-available setups. [![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/pro-tier.md) [![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://youtu.be/UIzrW9otvYM?si=P1too6QjZ5r9AHtB) ## Enterprise -Contact us +The Enterprise Tier is fully optimized for mission-critical applications, providing the highest levels of security, availability, and dedicated operational support. Schedule a call with a FalkorDB solutions architect to learn more. + +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/blob/Cloud-Docs/cloud/enterprise-tier.md) +[![Watch Demo](https://img.shields.io/badge/Watch%20Demo-black?style=for-the-badge)](https://youtu.be/fu_8CLFKYSs?si=G7K6dN1i5tyqXTfC) From 60c754a64388fe3d2ff327d769ffdabe4c86ca4c Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:56:43 +0200 Subject: [PATCH 054/107] Revise features documentation by removing sections Removed sections on Clusters, Availability, Deployment Options, Scalability, Backups, and Monitoring & Analytics from features documentation. --- cloud/features.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cloud/features.md b/cloud/features.md index c4c3638d..c311fc72 100644 --- a/cloud/features.md +++ b/cloud/features.md @@ -52,14 +52,6 @@ Organizations with security requirements need VPC deployment to control network You deploy FalkorDB into your existing VPC, and the database becomes accessible only through your private network. Your applications connect using private IP addresses instead of public endpoints. -## Clusters - -## Availability - -## Deployment Options - -## Scalability - ## Persistence Persistence ensures your graph data survives system restarts, crashes, or failures by writing changes to disk. Without persistence, you lose all data when the database stops. @@ -67,11 +59,6 @@ Any application storing important data requires persistence to maintain durabili FalkorDB persists data through regular snapshots and transaction logs. These mechanisms guarantee that committed transactions remain safe even if the system crashes immediately afterward. -## Backups - -## Monitoring & Analytics - -### Additional Features & Services #### Solution Architecture Solution architecture support helps you design how FalkorDB integrates with your broader application infrastructure. This guidance covers connection patterns, data modeling approaches, and best practices for specific use cases. From d5abf451c06617c134cd8a82eb1232861d104752 Mon Sep 17 00:00:00 2001 From: Dandan7 <182233217+danshalev7@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:57:19 +0200 Subject: [PATCH 055/107] Add 'Learn More' badge to cloud index Added a 'Learn More' badge linking to the features documentation. --- cloud/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloud/index.md b/cloud/index.md index 91d17fbb..f3a1477e 100644 --- a/cloud/index.md +++ b/cloud/index.md @@ -21,6 +21,8 @@ Get started with FalkorDB's cloud offering. The platform provides several enterp | **Support & Monitoring** | - Dedicated Support
- Advanced Monitoring
- Dedicated Account Manager | | ☁️ **Cloud Providers** | - AWS
- GCP
- Azure
- BYOC (AWS, GCP) | +[![Learn More](https://img.shields.io/badge/Learn%20More-8A2BE2?style=for-the-badge)](https://github.com/FalkorDB/docs/edit/Cloud-Docs/cloud/features.md) + --- ### Billing & Setup From 20049664ba41905cb8764e99e935c103b1ce5e2f Mon Sep 17 00:00:00 2001 From: Roi Lipman Date: Sun, 21 Dec 2025 21:19:25 +0200 Subject: [PATCH 056/107] [WIP] UDFs --- udfs/udfs.md | 416 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100644 udfs/udfs.md diff --git a/udfs/udfs.md b/udfs/udfs.md new file mode 100644 index 00000000..6b98306b --- /dev/null +++ b/udfs/udfs.md @@ -0,0 +1,416 @@ +# UDFs - User Defined Functions + +Every databases comes with a set of built-in functions, for example among FalkorDB functions you'll find: +`abs` - computes the absolute value of a number +`pow` - computes v^x +`trim` - removes leading and trailing spaces. + +These are baked into the DB and are part of its source code, introducing a new function e.g. `UpperCaseOdd`isn't always trivial, +the function needs to be usable to a wide audiance for it to be considered, in the past we've rejected requests for adding new functions as these were too specific and we didn't believe they've added a great value for most of our users. + +But now with the support of UDFs everyone can extends FalkorDB's functionality with their own set of functions. Following is an introduction to UDFs, how to manage & use them within FalkorDB. + + +## Example +Following is a complete example which loads a new UDF library "StringUtils" that includes a single function "UpperCaseOdd", once loaded the script puts it to use. + +```python +from falkordb import FalkorDB + +# Connect to FalkorDB +db = FalkorDB(host='localhost', port=6379) + +# Define UDF library name & script +lib = "StringUtils" + +# UpperCaseOdd implementation in JavaScript +script = """ +function UpperCaseOdd(s) { + return s.split('') + .map((char, i) => { + if (i % 2 !== 0) { + return char.toUpperCase(); + } + return char; + }) + .join(''); +}; + +// expose UDF to FalkorDB +falkor.register('UpperCaseOdd', UpperCaseOdd); +""" + +# Load UDF into the database +db.udf_load(lib, script) + +# Call UDF +graph = db.select_graph("G") +s = graph.query("RETURN StringUtils.UpperCaseOdd('abcdef)").result_set[0][0] +print(f"s: {s}") # prints 'AbCdEf' +``` + +## GRAPH.UDF LOAD [REPLACE]