Weaviate 1.19.0
We are happy to announce the release of Weaviate 1.19
, which brings a set of great features, performance improvements, and fixes.
If you like your content brief and to the point, here is the TL;DR of this release:
- Group by arbitrary property – The groupBy option has been introduced to Get object retrieval, so you can group search results by any property.
- New (or improved) Data Types – Data types changes with text having faster filtering & more tokenization options while deprecating string to reduce complexity, and adding uuid to allow efficient uuid storage.
- Generative Cohere Module – Combines the best of Weaviate, retrieving and searching relevant documents with the generative capabilities of the models that Cohere is cooking up!
- Tunable Consistency for Vector Search and GraphQL Get Requests – Consistency tuning with replication is now available for vector search with Get requests.
- gRPC API support(experimental) – gRPC API support slowly being trialed, with some big potential for speedups.
- Other Improvements and Bug Fixes – fixes and improvements delivered since
1.18
.
Read below to learn more about each of these points in more detail.
Keep in mind that after upgrading to v1.19
a downgrade to v1.18
will no longer be supported. If you anticipate having to downgrade, please create a backup before upgrading! If a backup is done with v1.18
before upgrading, you can always go back to v1.18
if you wish.
- With the
string
->text
migration, downgrading after upgrading will not work. - With the prop tracker fixes (bm25), once migrated you can’t downgrade again.
Group by arbitrary property
With the introduction of this feature, you can now group Get
search results based on a specific property.
Take a collection of Passage
objects for example, each object belonging to a Document
. If searching through Passage
objects, you can group the results according to any property of the Passage
, including the cross-reference property that represents the Document
each Passage
is associated with.
The groups
and objectsPerGroup
limits are customizable. So in this example, you could retrieve the top 1000 objects and group them to identify the 3 most relevant Document
objects, based on the top 3 Passage
objects from each Document
.
This functionality offers the advantage of maintaining granular search results by searching through detailed or segmented objects (e.g., Passage
), while also enabling you to step back and view the broader context of the objects (e.g., Document
).
An example GraphQL query is shown below:
{
Get{
Passage(
limit: 100
nearObject:{
id: "00000000-0000-0000-0000-000000000001"
}
groupBy:{
path:["content"]
groups:2
objectsPerGroup:2
}
){
_additional{
group{
id
count
groupValue
maxDistance
minDistance
hits{
content
ofDocument {
... on Document{
_additional{
id
}
}
}
_additional{
id
distance
}
}
}
}
}
}
}
And a corresponding example response is also shown below:
{
"data": {
"Get": {
"Passage": [
{
"_additional": {
"group": {
"count": 1,
"groupValue": "Content of passage 1",
"hits": [
{
"_additional": {
"distance": 0,
"id": "00000000-0000-0000-0000-000000000001"
},
"content": "Content of passage 1",
"ofDocument": [
{
"_additional": {
"id": "00000000-0000-0000-0000-000000000011"
}
}
]
}
],
"id": 0,
"maxDistance": 0,
"minDistance": 0
},
"id": "00000000-0000-0000-0000-000000000001"
}
},
{
"_additional": {
"group": {
"count": 1,
"groupValue": "Content of passage 2",
"hits": [
{
"_additional": {
"distance": 0.00078231096,
"id": "00000000-0000-0000-0000-000000000002"
},
"content": "Content of passage 2",
"ofDocument": [
{
"_additional": {
"id": "00000000-0000-0000-0000-000000000011"
}
}
]
}
],
"id": 1,
"maxDistance": 0.00078231096,
"minDistance": 0.00078231096
},
"id": "00000000-0000-0000-0000-000000000002"
}
}
]
}
}
}
path
complexityKeep in mind that specifying a path
value that requires resolving a large number of objects may be computationally expensive. For instance, setting the path
above to ["ofDocument", "Document", "title"]
would require resolving all documents and may take considerably longer.
New (or improved) Data Types
We've made several enhancements to the way we handle data, including upgrades to the text
property and the introduction of dedicated uuid
data types.
Text / String changes
We have upgraded the text
property to offer more flexibility in tokenizing textual data for indexing. You can now choose from word
, whitespace
, lowercase
, and field
tokenization options. To simplify matters, we have deprecated the string
data type.
The available tokenization options for text
are:
word
(default): Keep alpha-numeric characters, lowercase them, and split by whitespace. (Same as the currenttext
behavior.)whitespace
: Split the text on whitespace. (Same asword
onstring
right now.)lowercase
: Lowercase the text and split on whitespace. (New)field
: Index the whole field after trimming whitespace characters. (Same as the currentstring
behavior.)
Faster filtering & index changes
We have introduced a roaring bitmap index for text
properties, which brings the fast filtering capabilities introduced in version 1.18
to text data. Internally, this is implemented using two separate (filterable
& searchable
) indexes, which replaces the existing index. You can configure the new indexFilterable
and indexSearchable
parameters to determine whether to create the roaring set index and the BM25-suitable Map index, respectively. (Both are enabled by default.)
The searchable index works also as fallback for text filtering, so filtering is still possible even if indexFilterable will be disabled. The downside, in this scenario is if you turn off the bitmap indexing, filtering by the text property will be slower.
How will upgrades work?
After upgrading a pre-v1.19
Weaviate to v1.19
, indexFilterable
+ indexSearchable
will be set based on the value of indexInverted
, meaning true
-> true
+true
, false
-> false
+false
, null
-> null
+null
. (A null
will use the default, which is to turn it on.)
indexFilterable
and indexSearchable
are available for all types of data, although searchable is only relevant for text
/text[]
, and in other cases it will be simply ignored.
Since filterable & searchable are separate indexes, filterable does not exist in Weaviate instances upgraded from pre-v1.19
to v1.19
. The missing filterable
index can be created though on startup for all text/text[]
properties if env variable INDEX_MISSING_TEXT_FILTERABLE_AT_STARTUP is set (to true
).
While building the filterable
index, Weaviate will work in readonly mode (similarly to re-indexing sets to roaring sets on pre-v1.18
to v1.18
migration).
Deprecation of string
Existing string
classes can be migrated according to the tokenization rules above during the first startup. If a user specifies string
for a new class, it will be stored as text
with field
tokenization, and a deprecation warning will be shown.
Dedicated UUID Data Types
We have introduced dedicated uuid
and uuid[]
data types, reducing the storage space required by more than half.
uuid
details:
- Each
uuid
is a 128-bit (16-byte) number. - The filterable index uses roaring bitmaps.
- Please note that it is currently not possible to aggregate or sort by
uuid
oruuid[]
types.
Generative Cohere Module
With Weaviate 1.19.0
we are very excited to announce that the generative-cohere
module is now available for use! This module, similar to our previous generative module, enables you to leverage the power of Large Language Models on your own customized datasets and for specific use cases.
The generative-cohere
module combines the best of Weaviate, retrieving and searching relevant documents with the generative capabilities of the models that Cohere is cooking up! By integrating a general-purpose LLM with a vector database like Weaviate, you can utilize the model's power to carry out tasks in the context of your own data housed in Weaviate!
The generative-cohere
module can be used to get Cohere’s command-xlarge-nightly
model to answer prompts grounded in the context of knowledge provided by Weaviate search results.
The process consists of two steps: first, we query Weaviate to extract context by filtering a subset of your data that has knowledge relevant to a specific prompt. Secondly, we send the prompt as well as the filtered subset of documents from step one directly to the LLM model using Cohere’s API to accomplish the task specified in the prompt.
To get started with the module you simply need to include it when specifying the config for the Weaviate instance and provide you Cohere API key prior to querying. Other models that can be used with the module include command-xlarge-beta
and command-xlarge
. The module can be used to generate responses from the LLM for each returned document from Weaviate, using singleResult
, or a grouped response that uses all returned documents together as context, using groupedResult
.
See below for an example of how you can use the module. For more information on how to set up and use the module please refer to the documentation.
Example Query:
{
Get{
Article(
nearText: {
concepts: ["Italian food"]
}
limit: 1
) {
title
summary
_additional {
generate(
singleResult: {
prompt: """
Describe the following as a Facebook Ad: {summary}
"""
}
) {
singleResult
error
}
}
}
}
}
Corresponding Response:
{
"data": {
"Get": {
"Article": [
{
"_additional": {
"generate": {
"error": null,
"singleResult": "Italian food, as we know it today, might be a relatively modern concept. But it's hard to deny that there's something special about it. It could be the way the pasta tastes or the way the sauce smells. It could be the way the cheese stretches or the way the bread soaks up the sauce. Whatever it is, Italian food has a way of capturing our hearts and our stomachs. So if you're looking for a way to spice up your meal routine, why not try Italian? You might just find that it's your new favorite cuisine."
}
},
"summary": "Even the emoji for pasta isn't just pasta -- it's a steaming plate of spaghetti heaped with tomato sauce on top. But while today we think of tomatoes as inextricably linked to Italian food, that hasn't always been the case. \"People tend to think Italian food was always as it is now -- that Dante was eating pizza,\" says Dr Eva Del Soldato , associate professor of romance languages at the University of Pennsylvania, who leads courses on Italian food history. In fact, she says, Italy's complex history -- it wasn't unified until 1861 -- means that what we think of Italian food is, for the most part, a relatively modern concept. Diego Zancani, emeritus professor of medieval and modern languages at Oxford University and author of \"How We Fell in Love with Italian Food,\" agrees.",
"title": "How this fruit became the star of Italian cooking"
}
]
}
}
}
Tunable Consistency for Vector Search and GraphQL Get Requests
To help you optimize Weaviate according to your consistency and speed requirements, we provide the following consistency settings:
ONE
- reads/writes return the result from the first node that respondsQUORUM
- reads/writes succeed after a majority of nodes (replication_factor/2 + 1
) respondALL
- all replicas must respond
We initially introduced this consistency tuning feature in the [1.17
release] (TODO - LINK TO 1.17 blog) and later expanded it to support all read and write REST operations in the [1.18
release] (TODO - LINK TO 1.18 blog).
In the 1.19
release, we further extend tunable consistency support to include vector search and GraphQL Get requests.
gRPC API support (experimental)
We're excited to share an under-the-hood improvement that could make your experience even better.
Starting with version 1.19
, Weaviate is introducing support for the gRPC (gRPC Remote Procedure Calls) API. While there won't be any user-facing API changes, you may notice that your queries are executed even faster than before.
Without diving too deep into technicalities, the sources of speedup include: reduced encoding/decoding compute requirements at the protocol level, improved parsing efficiency, and specific optimizations in certain Python implementations.
Our internal tests indicate an approximate 2-3x speedup in queries where gRPC is implemented. We plan to gradually expand gRPC support, so if you notice your queries are running faster in the future, you'll know why. 😉
But we will be adding support to all clients going forward, as well as to additional endpoints.
Other Improvements and Bug Fixes
Since Weaviate 1.18
, we have released four patches that include various changes and bug fixes.
Node Allocation
We’ve introduced a new feature in Weaviate that offers a more efficient approach to node allocation. Rather than randomly selecting a node, Weaviate will now try to select the node with the most available resources. This only applies when creating a new class, rather than when adding more data to an existing single class. The current implementation only considers the disk space. In the future, we can add more data points like memory consumption and others.
This improvement was part of the 1.18.1
release.
Improved Multi-Class Support
Previously, Weaviate would struggle when adding many “1,000s of” classes. We identified and fixed various issues to fix this. Issues related to many-class can generally be grouped into three distinct areas of concern: 1. Higher than expected memory usage, 2. Cycle spam, 3. Lagging schema deletes. The overview of each section can be found here.
Fixes for BM25
As an ongoing effort to improve BM25, we realized there was an error when calculating the average length of a property. There are two issues:
- If there are too many properties, the BM25 component has errors.
- If there are zero-length properties, the BM25 component can return incorrect mean values.
To fix these problems, the property length tracker has been completely replaced. This is a non-breaking change that seamlessly migrates at startup. This change makes BM25 searches more accurate.
This change is part of the 1.19.0
release.
Release Notes for all Patches
The above features highlighted a few changes that were included in the patch releases. For more details on each release, you can check out the release notes: