Cross-references
Overview
You can use cross-references to establish directional relationships between classes, for example from a Book
to its Author
, or from an Author
to their Book
s.
To define a cross-reference, you must:
- At the class level, set up a
cross-reference
property in one class (from
) referring to another (to
) class, then - For individual objects, establish the cross-reference between a particular object of the
from
class, to an object of theto
class, using their ids.
For classes where multi-tenancy is enabled, you can establish a cross-reference from a multi-tenancy class object to:
- A non-multi-tenancy class object, or
- A multi-tenancy class object belonging to the same tenant.
See Manage data: multi-tenancy operations for details on how.
Creating cross-references does not affect object vectors in either direction.
Data set
The example for this howto is a dataset consisting of 1000 questions & answers from the popular quiz show "Jeopardy!". The two classes of interest are: JeopardyQuestion
and JeopardyCategory
. Let's pick some objects of interest:
Questions:
{
"answer": "San Francisco",
"question": "This city's Cable Car Museum...",
"_additional": {
"id": "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
}
}
Categories:
[
{
"title": "U.S. CITIES",
"_additional": {
"id": "20ffc68d-986b-5e71-a680-228dba18d7ef"
}
},
{
"title": "MUSEUMS",
"_additional": {
"id": "fec50326-dfa1-53c9-90e8-63d0240bd933"
}
}
]
Add a one-way cross-reference property
This requires adding one reference property from
a class referring to
another, and adding one cross-reference per object pair.
To add a cross-reference property in the class definition, specify its dataType
as the name of another class in the schema.
For example to specify the cross-reference from JeopardyQuestion
to JeopardyCategory
:
import weaviate.classes as wvc
client.collections.create(
name="JeopardyQuestion",
description="A Jeopardy! question",
properties=[
wvc.Property(name="question", data_type=wvc.DataType.TEXT),
wvc.Property(name="answer", data_type=wvc.DataType.TEXT),
wvc.ReferenceProperty(
name="hasCategory",
target_collection="JeopardyCategory"
)
]
)
To add a cross-reference from an object to another, specify its source class and id, the property name, and the class and id of the target object. In the example below, we'll add (not set) the "U.S. CITIES" category to the "San Francisco" Q&A (which by default only has the "MUSEUMS" category):
- Python (v4)
- Python (v3)
- JavaScript/TypeScript
- Java
- Go
import weaviate.classes as wvc
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
questions = client.collections.get("JeopardyQuestion")
questions.data.reference_add(
from_uuid=sf_id,
from_property="hasCategory",
ref=wvc.Reference.to(uuids=us_cities_id)
)
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
client.data_object.reference.add(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_name="JeopardyCategory",
to_uuid=us_cities_id,
)
await client.data
.referenceCreator()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('20ffc68d-986b-5e71-a680-228dba18d7ef')
.payload()
)
.do();
String sfId = "00ff6900-e64f-5d94-90db-c8cfa3fc851b";
String usCitiesId = "20ffc68d-986b-5e71-a680-228dba18d7ef";
client.data().referenceCreator()
.withClassName("JeopardyQuestion")
.withID(sfId)
.withReferenceProperty("hasCategory")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(usCitiesId)
.payload())
.run();
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"
client.Data().ReferenceCreator().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(usCitiesID).
Payload()).
Do(ctx)
Add two-way cross-references
This requires adding reference properties in both directions, and adding two cross-references per object pair (from
A -> to
B and from
B -> to
A).
To define a bidirectional reference between two classes, add a property to each class with the dataType
set to the name of the other class:
JeopardyCategory
collection:
import weaviate.classes as wvc
category = client.collections.create(
name="JeopardyCategory",
description="A Jeopardy! category",
properties=[
wvc.Property(name="title", data_type=wvc.DataType.TEXT)
]
)
JeopardyQuestion
collection:
client.collections.create(
name="JeopardyQuestion",
description="A Jeopardy! question",
properties=[
wvc.Property(name="question", data_type=wvc.DataType.TEXT),
wvc.Property(name="answer", data_type=wvc.DataType.TEXT),
wvc.ReferenceProperty(
name="hasCategory",
target_collection="JeopardyCategory"
)
]
)
Update JeopardyCategory
to add the reference to JeopardyQuestion
:
# Add the reference to JeopardyQuestion, after it was created
category.config.add_property(
wvc.ReferenceProperty(
name="hasQuestion",
target_collection="JeopardyQuestion"
)
)
To set up a two-way cross-reference between two objects, set each cross-reference in turn:
- Python (v4)
- Python (v3)
- JavaScript/TypeScript
- Java
- Go
import weaviate.classes as wvc
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
# For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
questions = client.collections.get("JeopardyQuestion")
questions.data.reference_add(
from_uuid=sf_id,
from_property="hasCategory",
ref=wvc.Reference.to(us_cities_id)
)
# For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
categories = client.collections.get("JeopardyCategory")
categories.data.reference_add(
from_uuid=us_cities_id,
from_property="hasQuestion",
ref=wvc.Reference.to(sf_id)
)
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
# First, add the "hasQuestion" cross-reference property to the JeopardyCategory class
client.schema.property.create("JeopardyCategory", {
"name": "hasQuestion",
"dataType": ["JeopardyQuestion"]
})
# For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
client.data_object.reference.add(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_name="JeopardyCategory",
to_uuid=us_cities_id,
)
# For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
client.data_object.reference.add(
from_class_name="JeopardyCategory",
from_uuid=us_cities_id,
from_property_name="hasQuestion",
to_class_name="JeopardyQuestion",
to_uuid=sf_id,
)
// First, add the "hasQuestion" cross-reference property to the JeopardyCategory class
await client.schema
.propertyCreator()
.withClassName('JeopardyCategory')
.withProperty({
name: 'hasQuestion',
dataType: ['JeopardyQuestion'],
})
.do();
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
await client.data
.referenceCreator()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('20ffc68d-986b-5e71-a680-228dba18d7ef')
.payload()
)
.do();
// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
await client.data
.referenceCreator()
.withClassName('JeopardyCategory').withId('20ffc68d-986b-5e71-a680-228dba18d7ef')
.withReferenceProperty('hasQuestion')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyQuestion')
.withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.payload()
)
.do();
String sfId = "00ff6900-e64f-5d94-90db-c8cfa3fc851b";
String usCitiesId = "20ffc68d-986b-5e71-a680-228dba18d7ef";
// First, add the "hasQuestion" cross-reference property to the JeopardyCategory class
client.schema().propertyCreator()
.withClassName("JeopardyCategory")
.withProperty(Property.builder()
.name("hasQuestion")
.dataType(Collections.singletonList("JeopardyQuestion"))
.build())
.run();
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
client.data().referenceCreator()
.withClassName("JeopardyQuestion")
.withID(usCitiesId)
.withReferenceProperty("hasCategory")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(sfId)
.payload())
.run();
// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
client.data().referenceCreator()
.withClassName("JeopardyCategory")
.withID(usCitiesId)
.withReferenceProperty("hasQuestion")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyQuestion")
.withID(usCitiesId)
.payload())
.run();
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"
// First, add the "hasQuestion" cross-reference property to the JeopardyCategory class
client.Schema().PropertyCreator().
WithClassName("JeopardyCategory").
WithProperty(&models.Property{
Name: "hasQuestion",
DataType: []string{"JeopardyQuestion"},
}).
Do(ctx)
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
client.Data().ReferenceCreator().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(usCitiesID).
Payload()).
Do(ctx)
// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
client.Data().ReferenceCreator().
WithClassName("JeopardyCategory").
WithID(usCitiesID).
WithReferenceProperty("hasQuestion").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyQuestion").
WithID(sfID).
Payload()).
Do(ctx)
Add multiple (one-to-many) cross-references
To add a one-to-many cross-reference relationship, add to the source object each of the cross-references to the target objects that you need.
For example, to mark that the "San Francisco" Q&A belongs to multiple categories, e.g. "US. CITIES" and "MUSEUMS":
- Python (v4)
- Python (v3)
- JavaScript/TypeScript
- Java
- Go
import weaviate.classes as wvc
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
questions = client.collections.get("JeopardyQuestion")
questions.data.reference_add(
from_uuid=sf_id,
from_property="hasCategory",
ref=wvc.Reference.to([us_cities_id, museums_id]) # add multiple references
)
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
us_cities_id = "20ffc68d-986b-5e71-a680-228dba18d7ef"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
# Add to "San Francisco" the "U.S. CITIES" category
client.data_object.reference.add(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_name="JeopardyCategory",
to_uuid=us_cities_id,
)
# Add the "MUSEUMS" category as well
client.data_object.reference.add(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_name="JeopardyCategory",
to_uuid=museums_id,
)
// Add to "San Francisco" the "U.S. CITIES" category
await client.data
.referenceCreator()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('20ffc68d-986b-5e71-a680-228dba18d7ef')
.payload()
)
.do();
// Add the "MUSEUMS" category as well
await client.data
.referenceCreator()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('fec50326-dfa1-53c9-90e8-63d0240bd933')
.payload()
)
.withConsistencyLevel('ALL')
.do();
String sfId = "00ff6900-e64f-5d94-90db-c8cfa3fc851b";
String usCitiesId = "20ffc68d-986b-5e71-a680-228dba18d7ef";
String museumsId = "fec50326-dfa1-53c9-90e8-63d0240bd933";
// Add to "San Francisco" the "U.S. CITIES" category
client.data().referenceCreator()
.withClassName("JeopardyQuestion")
.withID(sfId)
.withReferenceProperty("hasCategory")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(usCitiesId)
.payload())
.run();
// Add the "MUSEUMS" category as well
client.data().referenceCreator()
.withClassName("JeopardyQuestion")
.withID(sfId)
.withReferenceProperty("hasCategory")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(museumsId)
.payload())
.run();
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"
// Add to "San Francisco" the "U.S. CITIES" category
client.Data().ReferenceCreator().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(usCitiesID).
Payload()).
Do(ctx)
// Add the "MUSEUMS" category as well
client.Data().ReferenceCreator().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(museumsID).
Payload()).
Do(ctx)
Delete a cross-reference
Deleting a cross-reference requires specifying the parameters that define the cross-reference.
To delete a cross-reference, specify the class, id and cross-reference property name of the source object, and the class and id of the target object:
- Python (v4)
- Python (v3)
- JavaScript/TypeScript
- Java
- Go
import weaviate.classes as wvc
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
# From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
questions = client.collections.get("JeopardyQuestion")
questions.data.reference_delete(
from_uuid=sf_id,
from_property="hasCategory",
ref=wvc.Reference.to(museums_id)
)
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
# From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
# https://weaviate-python-client.readthedocs.io/en/stable/weaviate.data.references.html#weaviate.data.references.Reference.delete
sf = client.data_object.get(uuid=sf_id, class_name="JeopardyQuestion")
cat = client.data_object.get(uuid=museums_id, class_name="JeopardyCategory")
client.data_object.reference.delete(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_name="JeopardyCategory",
to_uuid=museums_id,
)
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
await client.data
.referenceDeleter()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('fec50326-dfa1-53c9-90e8-63d0240bd933')
.payload()
)
.do();
String sfId = "00ff6900-e64f-5d94-90db-c8cfa3fc851b";
String museumsId = "fec50326-dfa1-53c9-90e8-63d0240bd933";
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
client.data().referenceDeleter()
.withClassName("JeopardyQuestion")
.withID(sfId)
.withReferenceProperty("hasCategory")
.withReference(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(museumsId)
.payload())
.run();
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
client.Data().ReferenceDeleter().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(museumsID).
Payload()).
Do(ctx)
What happens if the to
object is deleted?
If an object is deleted, cross-references to it will be left intact. A Get query using the inline fragment syntax will correctly retrieve only fields in the existing cross-references objects, but getting the object by ID will show all cross-references, whether the objects they point to exist or not.
Update a cross-reference
To update the cross-references stored in a property of an object, specify the object's UUID, class name and cross-references property name, as well as the new list of cross-referenced UUIDs and their class (if all objects are of the same class) or classes (one class per each UUID):
- Python (v4)
- Python (v3)
- JavaScript/TypeScript
- Java
- Go
import weaviate.classes as wvc
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
# In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
questions = client.collections.get("JeopardyQuestion")
questions.data.reference_replace(
from_uuid=sf_id,
from_property="hasCategory",
ref=wvc.Reference.to(museums_id)
)
sf_id = "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museums_id = "fec50326-dfa1-53c9-90e8-63d0240bd933"
# In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
# https://weaviate-python-client.readthedocs.io/en/stable/weaviate.data.references.html#weaviate.data.references.Reference.update
client.data_object.reference.update(
from_class_name="JeopardyQuestion",
from_uuid=sf_id,
from_property_name="hasCategory",
to_class_names=["JeopardyCategory"],
to_uuids=[museums_id],
)
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
await client.data
.referenceReplacer()
.withClassName('JeopardyQuestion').withId('00ff6900-e64f-5d94-90db-c8cfa3fc851b')
.withReferenceProperty('hasCategory')
.withReferences([
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId('fec50326-dfa1-53c9-90e8-63d0240bd933')
.payload(),
])
.do();
String sfId = "00ff6900-e64f-5d94-90db-c8cfa3fc851b";
String museumsId = "fec50326-dfa1-53c9-90e8-63d0240bd933";
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
client.data().referenceReplacer()
.withClassName("JeopardyQuestion")
.withID(sfId)
.withReferenceProperty("hasCategory")
.withReferences(client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(museumsId)
.payload())
.run();
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
client.Data().ReferenceReplacer().
WithClassName("JeopardyQuestion").
WithID(sfID).
WithReferenceProperty("hasCategory").
WithReferences(&models.MultipleRef{
client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(museumsID).
Payload(),
}).
Do(ctx)
Batch creation
Cross-references can be created using batches just like data objects. This can be done by using the same batch process, but by adding cross-references to the batch instead of data objects.
Please see the batch import how-to for more on batch imports.
Retrieve cross-references
Cross-references in Weaviate are not themselves objects, but properties of objects. As such, you can retrieve cross-reference in one of two ways:
- Retrieve the object that it belongs to. This will return the cross-reference as a property of the object.
- Retrieve the cross-reference as a part of a query. Just as you can retrieve any other property of search results, you can retrieve cross-reference properties.