The first On-Device Vector Database: ObjectBox 4.0

The first On-Device Vector Database: ObjectBox 4.0

The new on-device vector database enables advanced AI applications on small restricted devices like mobile phones, Raspberry Pis, medical equipment, IoT gadgets and all the smart things around you. It is the missing piece to a fully local AI stack and the key technology to enable AI language models to interact with user specific data like text and images without an Internet connection and cloud services.

An AI Technology Enabler

Recent AI language models (LLMs) demonstrated impressive capabilities while being small enough to run on e.g. mobile phones. Recent examples include Gemma, Phi3 and OpenELM. The next logical step from here is to use these LLMs for advanced AI applications that go beyond a mere chat. A new generation of apps is currently evolving. These apps create “flows” with user specific data and multiple queries to the LLM to perform complex tasks. This is also known as RAG (retrieval augmented generation), which, in its simplest form, allows one to chat with your documents. And now, for the very first time, this will be possible to do locally on restricted devices using a fully fledged embedded database.

What is special about ObjectBox Vector Search?

We know restricted devices. Where others see limitations, we see the potential and we have repeatedly demonstrated creating superefficient software for these. And thus maximizing speed, minimizing resource use, saving battery life and CO2. With this knowledge, we approached vector search in a unique way.

Efficient memory management is the key. The challenge with vector data is that on the one hand, it consumes a lot of memory – while on the other hand, relevant vectors must be present in memory to compute distances between vectors efficiently. For this, we introduced a special multi-layered caching that gives the best performance for the full range of devices; from memory-constrained small devices to large machines that can keep millions of vectors in memory. This worked out so well that we saw ObjectBox outperform several vector databases built for servers (open source benchmarks coming soon). This is no small feat given that ObjectBox still holds up full ACID properties, e.g. caching must be transaction-aware.

Also, keep in mind that ObjectBox is a fully capable database that allows you to store complex data objects along with vectors. From an ObjectBox data model point of view, a vector is “just” another property type. This allows you to store all your data (vectors along with objects) in a single database. This “one database” approach also includes queries. You can already combine vector search with other conditions. Note that some limitations still apply with this initial release. Full hybrid search is close to being finished and will be part of one of the next releases.

In short, the following features make ObjectBox a unique vector database:

  • Embedded Database that runs inside your application without latency
  • Vector search based is state-of-the-art HNSW algorithm that scales very well with growing data volume
  • HNSW is tightly integrated within our internal database. Vector Search doesn’t just run “on top of database persistence”.
  • With this deep integration we do not need to keep all vectors in memory.
  • Multi-layered caching: if a vector is not in-memory, ObjectBox fetches it from disk.
  • Not just a vector database: you can store any data in ObjectBox, not just vectors. You won’t need a second database.
  • Low minimum hardware requirements: e.g. an old Raspberry Pi comfortably runs ObjectBox smoothly.
  • Low memory footprint: ObjectBox itself just takes a few MB of memory. The entire binary is only about 3 MB (compressed around 1 MB).
  • Scales with hardware: efficient resource usage is also an advantage when running on more capable devices like the latest phones, desktops and servers.
  • ObjectBox additionally offers commercial editions, e.g. a Server Cluster mode, GraphQL, and of course, ObjectBox Sync, our data synchronization solution.

Why is this relevant? AI anywhere & anyplace

With history repeating itself, we think AI is in a “mainframe era” today. Just like clunky computers from decades before, AI is restricted to big and very expensive machines running far away from the user. In the future, AI will become decentralized, shifting to the user and their local devices. To support this shift, we created the ObjectBox vector database. Our vision is a future where AI can assist everyone, anytime, and anywhere, with efficiency, privacy, and sustainability at its core.

What do we launch today?

Today, we are releasing ObjectBox 4.0 with Vector Search for a variety of languages:

*) We acknowledge Python’s popularity within the AI community and thus have invested significantly in our Python binding over the last months to make it part of this initial release. Since we still want to smooth out some rough edges with Python, we decided to label Python an alpha release. Expect Python to quickly catch up and match the comfort of our more established language bindings soon (e.g. automatic ID and model handling).

Let’s get you started right away? Check our Vector Search documentation to see how to use it!

One more thing: ObjectBox Open Source Database (OSS)

We are also very happy to announce that we will fully open source the core of ObjectBox. As a company we follow the open core model. Since we still have some cleaning up to do, this will happen in one of the next releases, likely 4.1.

“Release week”

With today’s initial releases, we are far from done yet. Starting next Tuesday, you can  expect additional announcements from us. Follow us to get the news as soon as it is released.

What’s next?

This is our very first version of a “vector database”. And while we are very happy with this release, there are still so many things to do! For example, we will optimize vector search by adding vector quantization and integrate it more tightly with our data synchronization. We are also focusing on expanding our solution’s reach through strategic partnerships. If you think you are a good fit, let us know. And as always, we are very eager to get some feedback from you! Take care.

Data Viewer for Objects – announcing ObjectBox Admin

Data Viewer for Objects – announcing ObjectBox Admin

ObjectBox Admin (Docker container) allows you to analyze ObjectBox databases that run on desktop and server machines. Releasing ObjectBox Admin as a standalone Docker image makes it possible to run Admin on a larger number of platforms.

ObjectBox Admin is available as a Linux x86_64 Docker image, which runs on all common platforms including Windows and macOS. We offer a convenience script (objectbox-admin.sh) but it’s also simple enough to run it via plain Docker. See the docs for details, or get started by following this short tutorial.

Data Browser

The ObjectBox Admin Web App comprises a menu on the left (Data, Schema, Status, GraphQL…) and the corresponding content pane on the right-hand side.

ObjectBox Admin Web App (Data, Schema, Status, GraphQL...)

The data browser provides a table of objects of a specific type. By clicking on the Type we can select an entity type for viewing its entity objects.

WebAdmin_Data_Type

Next to the type selection is a small filter icon (the dashed triangle right of the type selection).

When selected, a query editor pops up that allows to filter data by adding a Property/Operator/Value expression.

ObjectBox Admin Filtering

When finished, click the check mark, and the data table gets updated with an active filter.

Data Filter

At the bottom, you will find a download link that exports the objects of the currently viewed box in JSON format.

DownloadDataAsJson

Schema Browser

You can get a detailed list of elements that make up an object type in the “Schema” pane.

Schema pane

In accordance with the “Data” pane, you can click on Type to select the schema of a specific entity type of your database.

Status

Base level database and ObjectBox Admin information can be viewed on the “Status” pane.

Status pane

GraphQL

The Docker-version of ObjectBox Admin offers a pane to query the database using GraphQL.

GraphQL Data Browser

ObjectBox Database Java 3.1 – Flex type

ObjectBox Database Java 3.1 – Flex type

We are happy to announce version 3.1 of ObjectBox for Java and Kotlin. The major feature of this version is the new Flex type. For a long time, ObjectBox worked on rigid data schemas, and we think that this is a good thing. Knowing what your data looks like is a feature – similar to programming languages that are statically typed. Fixed schemas make data handling more predictable and robust. Nevertheless, sometimes there are use cases which require flexible data structures. ObjectBox 3.1 allows exactly this.

Flex properties

Expanding on the string and flexible map support in 3.0.0, this release adds support for Flex properties where the type must not be known at compile time. To add a Flex property to an entity use Object in Java and Any? in Kotlin. Then at runtime store any of the supported types.

For example, assume a customer entity with a tag property:

Then set a String tag on one customer, and an Integer tag on another customer and just put them:

When getting the customer from its box the original type is restored. For simplicity the below example just casts the tag to the expected type:

A Flex property can be not justString or Integer. Supported types are all integers (Byte, Short, Integer, Long), floating point numbers (Float, Double), String and byte arrays.

It can also hold a List<Object> or a Map<String, Object> of those types. Lists and maps can be nested.

Behind the scenes Flex properties use a FlexBuffer converter to store the property value, so some limitations apply. See the FlexObjectConverter class documentation for details.

Query for map keys and values

If the Flex property contains integers or strings, or a list or map of those types, it’s also possible to do queries. For example, take this customer entity with a properties String to String map:

Why is properties not of type Object? ObjectBox supports using Map<String, String> (or Map<String, Object>) directly and will still create a Flex property behind the scenes.

Then put a customer with a premium property:

To query for any customers that have a premium key in their properties map, use the containsElement condition:

Or to only match customers where the map key has a specific value, here a specific premium tier, use the containsKeyValue condition:

What’s next?

ObjectBox database is free to use. Check out our docs and this video tutorial to get started today.

We strive to bring joy to mobile developers and appreciate all kinds feedback, both positive and negative. You can always raise an issue on GitHub or post a question on Stackoverflow. Otherwise, star the ObjectBox  Java database GitHub repo and up-vote the features you’d like to see in the next release.

 

Beginner C++ Database Tutorial: How to use ObjectBox

Beginner C++ Database Tutorial: How to use ObjectBox

Introduction

As a direct follow up from the ObjectBox database installation tutorial, today we’ll code a simple C++ example app to show how the database can be used. Before starting to program, let’s briefly overview what we want to achieve with this tutorial and what is the best way to work through it.

Overview of the app we want to build

In short, we will make a console calculator app with an option to save results into memory. These will be stored as objects of the Number class. Every Number will also have an ID for easy reference in future calculations. Apart from the function to make calculations, we will create a function to enter memory. It will list all the database entries and have an option to clear memory. By coding all of this, we will make use of such standard ObjectBox operations as put, get, getAll and removeAll.

Our program will consist of seven files: 

  • the FlatBuffers schema file, that defines the model of a class we want to store in the database
  • the header file, for class function definitions
  • the source file, for function implementation
  • the four files with objectbox binding code that will be created by objectbox-generator

How to use this tutorial

While looking at coding examples is useful in many cases, the best way to learn such a practical skill like programming is to solve problems independently. This is why we included an exercise for each step. You are encouraged to make the effort and do each of them, even if you don’t know the answer straight away. Only move to the next step after you test each part of your program and make sure that everything works as intended. Ideally, you should only use the code snippets presented here to check yourself or look for hints when you feel stuck. Bear in mind that sometimes there might be several different ways to achieve the same results. So if something that we ask you to do in this tutorial doesn’t work for you, try to come up with your own solution.

How to create the FlatBuffers file?

First, we’ll create the FlatBuffers schema (.fbs) for our app. This is required for the objectbox-generator to generate binding code that will allow us to use the ObjectBox library in our project. 

The FlatBuffers schema consists of a table, which defines the object we want to store in the database, and the properties of this object. Each property consists of a name and a type. We want to keep our example very simple, so just two properties is enough.

  1. To replicate a calculator’s memory, we want ObjectBox to store some numbers. We can define the Number object by giving the table a corresponding name.
  2. Inside the table, we want to have two properties: id and contents. The contents of each Number object is the number itself (double), while id is an ulong that our program will assign to each of them for easy identification.

Exercise: create a file called numbers.fbs and define the table in the format

Reveal code

Generating binding code

Now that the FlatBuffers file is ready, we can generate the binding code. To do this, run the objectbox-generator for our FlatBuffers file:

The following files will be generated:

  • objectbox-model.h
  • objectbox-model.json
  • numbers.obx.hpp
  • numbers.obx.cpp

The header file

This is where the main chunk of our code will be. It will contain the Calculator class and all the function definitions.

  1. Start by including the three ObjectBox header files: objectbox.hpp, objectbox-model.h and numbers.obx.hpp. Our whole program will be based on one class, called Calculator. It should only have two private members: Store and Box. Store is a reference to the database and will manage Boxes. Each Box stores objects of a particular class. In this example, we only need one Box. Let’s call it numberBox, as it will store Numbers that we want to save in the memory of our calculator.

Exercise: create a file called calculator.hpp and define the Calculator class with two private members: reference to the obx library member Store and a Box of Numbers.

Reveal code

2. After the constructor, we define the run function. It will be responsible for the menu of our program. There should be two main options: to perform calculations and enter memory. As discussed above, we want this app to do two things: perform calculations and show memory. We’ll define these as separate functions, called Calculate and Memory. The first one is quite standard, so we won’t go into a detailed explanation here. The only thing you should keep in mind is that we need to account for the case when the user wants to  operate on a memory item. To deal with this, we’ll process input in a function called processInput.

Exercise: define the parametrised constructor which takes a reference to Store as a parameter. Then define the run and Calculate functions.

Reveal code

3. The final part of this function is for saving results into memory. We start by asking the user if they want to do that. If the answer is positive, we create a new instance of Number and set the most recent result as a value of its contents. To save our object in the database, we can operate with put(object) on our Box. put is one of the standard ObjectBox operations, which is used for creating new objects and overwriting existing ones. 

Exercise: create an option to store the result in memory, making use of the ObjectBox put operation.

Reveal code

4. Next, we should define processInput, which will read input as a string and check whether it has the right format. Now, to make it recognise the memory items, we have to come up with a standard format for these. Remember, we defined an ID property for our Numbers. Every number in our database has an ID, so we can refer to them as, e.g. m1, m2, m3 etc. To read the numbers from memory, we can make use of the get(obx_id) operation. It returns a unique pointer to the corresponding Number, whose contents we need to access and use as our operand.

Exercise: define the processInput function, which detects when something like m1 was used as an operand and updates x, y, and op according to the input.

Reveal code

5. The last function in our header file will be Memory. It should list all the numbers contained in the database and have an option to clear data. We can read all the database entries by calling the getAll ObjectBox operator. It returns a vector of unique pointers. To clear memory, you can simply operate with removeAll on our Box.

Exercise: define the Memory function, which lists all the memory items, and can delete all of them by request.

Reveal code

The source file

To tie everything together, we create a source (.cpp) file. It should contain only the main function that initialises the objectbox model, creates an instance of the Calculator app, and runs it. To create the ObjectBox model, use

then passing options as a parameter when you initialise the Store.

Exercise: create the source file

Reveal code

Final notes

Now you can finally compile and run your application. At this point, a good exercise would be to try and add some more functionality to this project. Check out the ObjectBox C++ documentation to learn more about the available operations.

After you’ve mastered ObjectBox DB, why not try ObjectBox Sync? Here is another tutorial from us, showing how easily you can sync between different instances of your cross platform app.

Other than that, if you spot any errors in this tutorial or if anything is unclear, please come back to us. We are happy to hear your thoughts.

Beginner C++ tutorial: ObjectBox installation

Beginner C++ tutorial: ObjectBox installation

This ObjectBox beginner tutorial is for people who have limited knowledge of C++ development (no prior experience with external libraries is required). It will walk you through the installation process of all the development tools needed to get started with ObjectBox on Windows. By the way, ObjectBox is a database with intuitive native APIs, so it won’t take you long to start using it.

Firstly, we will need to set up a Linux subsystem (WSL2) and install such tools as:

  • CMake, which will generate build files from the ObjectBox source code to work on Linux;
  • Git, which will download the source code from the ObjectBox repository.

Then, we will install ObjectBox and run a simple example in Visual Studio Code.

Windows Subsystem for Linux (WSL2)

In this section, you will set up a simple Linux subsystem that you can use to build Objectbox in C++.

  1. Install WSL (Note: this requires a reboot; it also configures a limited HyperV that may cause issues with e.g. VirtualBox).
    Warning: to paste e.g. a password to the Ubuntu setup console window, right-click the title bar and select Edit → Paste. CTRL + V may not work.
  2. (optional, but recommended) install Windows Terminal from Microsoft Store and use Ubuntu from there (does not have the copy/paste issue, also supports terminal apps better).
Windows Terminal in the Microsoft Store

3. Within Windows Terminal, open Ubuntu by choosing it from the dropdown menu.

Drop-down menu in Windows Terminal, through which a new tab for Ubuntu can be opened

4. Get the latest packages and upgrade:

5. Install build tools

Install ObjectBox using CMake

Now that you have WSL2 and all the packages, we can switch to VS Code and install ObjectBox with the help of CMake.

  1. In Ubuntu, create a new directory and then open it in Visual Studio Code:

2. Install the following extensions:

Extensions tab in Visual Studio Code, showing what needs to be installed in this tutorial: C/C++, CMake Tools and Remote - WSL

3. Create a text file called CMakeLists.txt with the following code. It will tell CMake to get the ObjectBox source code from its Git repository and link the library to your project.

4. Create a simple main.cpp file that will help us verify the setup:

5. Follow this official guide for VS code and CMake to select Clang as the compiler, configure and build ObjectBox. As a result, .vscode and build folders will be generated. So your directory should now look like this:

Explorer tab in Visual Studio Code, showing the two new folders that were generated after a successful build

Running the tasks-list app example

Finally, we can check that everything works and run a simple example.

1. Click the “Select target to launch” button on the status bar and select “myapp” from the dropdown menu. Then launch it. You should see it output the correct version as in the screenshot.

"Select launch target" menu in Visual Studio Code
Output of main.cpp, verifying the version of ObjectBox used and demonstrating that the C++ build files were generated correctly.

2. Before proceeding with the example, you need to download the most recent ObjectBox generator for Linux from releases. Then come back to the Windows Terminal and type

to open the current directory in Windows Explorer. Copy the objectbox-generator file in there.

3. Back in VS Code, you should now run the generator for the example code:

If you get a “permission denied” error, try this to make the generator file executable for your user:

4. Now choose objectbox-c-examples-tasks-cpp-gen as the target and run it. You should see the menu of a simple to-do list app as shown on the screenshot. It stores your tasks, together with their creation time and status. Try playing around with it and exploring the code of this example app to get a feel of how ObjectBox can be used.

Output of the Objectbox C++ tasks-list app example showing its menu with available commands

Note: if you see a sync error (e.g. Can not modify object of sync-enabled type “Task” because sync has not been activated for this store), please delete the first line from the tasklist.fbs file and run the objectbox generator once again. Or, if you want to try sync, apply for our Early Access Data Sync. There is a separate example (called objectbox-c-examples-tasks-cpp-gen-sync) that you can run after installing the Sync Server.

ObjectBox Database Java / Kotlin 3.0 + CRUD Benchmarks

ObjectBox Database Java / Kotlin 3.0 + CRUD Benchmarks

The Android database for superfast Java / Kotlin data persistence goes 3.0. Since our first 1.0-release in 2017 (Android-first, Java), we have released C/C++, Go, Flutter/Dart, Swift bindings, as well as Data Sync and we’re thrilled that ObjectBox has been used by over 800,000 developers.

We love our Java / Kotlin community ❤️ who have been with us since day one. So, with today’s post, we’re excited to share a feature-packed new major release for Java Database alongside CRUD performance benchmarks for MongoDB Realm, Room (SQLite) and ObjectBox.

What is ObjectBox?

ObjectBox is a high performance database and an alternative to SQLite and Room. ObjectBox empowers developers to persist objects locally on Mobile and IoT devices. It’s a NoSQL ACID-compliant object database with an out-of-the-box Data Sync providing fast and easy access to decentralized edge data (Early Access).

New Query API

A new Query API is available that works similar to our existing Dart/Flutter Query API and makes it easier to create nested conditions:

In Kotlin, the condition methods are also available as infix functions. This can help make queries easier to read:

Unique on conflict replace strategy

One unique property in an @Entity can now be configured to replace the object in case of a conflict (“onConflict”) when putting a new object.

This can be helpful when updating existing data with a unique ID different from the ObjectBox ID. E.g. assume an app that downloads a list of playlists where each has a modifiable title (e.g. “My Jam”) and a unique String ID (“playlist-1”). When downloading an updated version of the playlists, e.g. if the title of “playlist-1” has changed to “Old Jam”, it is now possible to just do a single put with the new data. The existing object for “playlist-1” is then deleted and replaced by the new version.

Built-in string array and map support

String array or string map properties are now supported as property types out-of-the-box. For string array properties it is now also possible to find objects where the array contains a specific item using the new containsElement condition.

Kotlin Flow, Android 12 and more

Kotlin extension functions were added to obtain a Flow from a BoxStore or Query:

Data Browser has added support for apps targeting Android 12.

For details on all changes, please check the ObjectBox for Java changelog.

Room (SQLite), Realm & ObjectBox CRUD performance benchmarks

We compared against the Android databases, MongoDB Realm and Room (on top of SQLite) and are happy to share that ObjectBox is still faster across all four major database operations: Create, Read, Update, Delete.

Android database comparative benchmarks for ObjectBox, Realm, and Room

We benchmarked ObjectBox along with Room 2.3.0 using SQLite 3.22.0 and MongoDB Realm 10.6.1 on an Samsung Galaxy S9+ (Exynos) mobile phone with Android 10. All benchmarks were run 10+ times and no outliers were discovered, so we used the average for the results graph above. Find our open source benchmarking code on GitHub and as always: feel free to check them out yourself. More to come soon, follow us on Twitter or sign up to our newsletter to stay tuned (no spam ever!).

Using a fast on-device database matters

A fast local database is more than just a “nice-to-have.” It saves device resources, so you have more resources (CPU, Memory, battery) left for other resource-heavy operations. Also, a faster database allows you to keep more data locally with the device and user, thus improving privacy and data ownership by design. Keeping data locally and reducing data transferal volumes also has a significant impact on sustainability.

Sustainable Data Sync

Some data, however, you might want or need to synchronize to a backend. Reducing overhead and synchronizing data selectively, differentially, and efficiently reduces bandwidth strain, resource consumption, and cloud / Mobile Network usage – lowering the CO2 emissions too. Check out ObjectBox Data Sync, if you are interested in an out-of-the-box solution.

Get Started with ObjectBox for Java / Kotlin Today

ObjectBox is free to use and you can get started right now via this getting-started article, or follow this video.

Already an ObjectBox Android database user and ready to take your application to the next level? Check out ObjectBox Data Sync, which solves data synchronization for edge devices, out-of-the-box. It’s incredibly efficient and (you guessed it) superfast 😎

We ❤️ your Feedback

We believe, ObjectBox is super easy to use. We are on a mission to make developers’ lives better, by building developer tools that are intuitive and fun to code with. Now it’s your turn: let us know what you love, what you don’t, what do you want to see next? Share your feedback with us, or check out GitHub and up-vote the features you’d like to see next in ObjectBox.