diff --git a/src/it/java/io/weaviate/integration/DataITest.java b/src/it/java/io/weaviate/integration/DataITest.java index 349ce5253..a0969655f 100644 --- a/src/it/java/io/weaviate/integration/DataITest.java +++ b/src/it/java/io/weaviate/integration/DataITest.java @@ -21,16 +21,14 @@ import io.weaviate.client6.v1.api.collections.ReferenceProperty; import io.weaviate.client6.v1.api.collections.VectorConfig; import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.data.BatchReference; import io.weaviate.client6.v1.api.collections.data.DeleteManyResponse; -import io.weaviate.client6.v1.api.collections.data.Reference; -import io.weaviate.client6.v1.api.collections.data.WriteWeaviateObject; +import io.weaviate.client6.v1.api.collections.data.ObjectReference; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.client6.v1.api.collections.query.Metadata; import io.weaviate.client6.v1.api.collections.query.Metadata.MetadataField; -import io.weaviate.client6.v1.api.collections.query.QueryMetadata; import io.weaviate.client6.v1.api.collections.query.QueryReference; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.client6.v1.api.collections.tenants.Tenant; import io.weaviate.containers.Container; @@ -66,20 +64,20 @@ public void testCreateGetDelete() throws IOException { Assertions.assertThat(object) .as("object has correct properties").get() .satisfies(obj -> { - Assertions.assertThat(obj.metadata().uuid()) + Assertions.assertThat(obj.uuid()) .as("object id").isEqualTo(id); - Assertions.assertThat(obj.metadata().vectors().getSingle(VECTOR_INDEX)) + Assertions.assertThat(obj.vectors().getSingle(VECTOR_INDEX)) .containsExactly(vector); Assertions.assertThat(obj.properties()) .as("has expected properties") .containsEntry("name", "john doe"); - Assertions.assertThat(obj.metadata().creationTimeUnix()) - .as("creationTimeUnix").isNotNull(); - Assertions.assertThat(obj.metadata().lastUpdateTimeUnix()) - .as("lastUpdateTimeUnix").isNotNull(); + Assertions.assertThat(obj.createdAt()) + .as("createdAt").isNotNull(); + Assertions.assertThat(obj.lastUpdatedAt()) + .as("lastUpdatedAt").isNotNull(); }); var deleted = artists.data.deleteById(id); @@ -114,7 +112,7 @@ public void testBlobData() throws IOException { cat -> cat.returnProperties("img")); Assertions.assertThat(got).get() - .extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .extractingByKey("img").isEqualTo(ragdollPng); } @@ -153,7 +151,7 @@ public void testReferences_AddReplaceDelete() throws IOException { persons.data.referenceAdd( john.uuid(), "hasFriend", - Reference.object(albie)); + ObjectReference.object(albie)); // Assert var johnWithFriends = persons.query.fetchObjectById(john.uuid(), @@ -163,10 +161,10 @@ public void testReferences_AddReplaceDelete() throws IOException { Assertions.assertThat(johnWithFriends).get() .as("friends after ADD") - .extracting(ReadWeaviateObject::references).extracting("hasFriend") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .extracting(WeaviateObject::references).extracting("hasFriend") + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) .hasSize(1) - .first().extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .first().extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .returns("albie", friend -> friend.get("name")); // Act: replace reference @@ -174,7 +172,7 @@ public void testReferences_AddReplaceDelete() throws IOException { persons.data.referenceReplace( john.uuid(), "hasFriend", - Reference.object(barbara)); + ObjectReference.object(barbara)); johnWithFriends = persons.query.fetchObjectById(john.uuid(), query -> query.returnReferences( @@ -183,17 +181,17 @@ public void testReferences_AddReplaceDelete() throws IOException { Assertions.assertThat(johnWithFriends).get() .as("friends after REPLACE") - .extracting(ReadWeaviateObject::references).extracting("hasFriend") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .extracting(WeaviateObject::references).extracting("hasFriend") + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) .hasSize(1) - .first().extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .first().extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .returns("barbara", friend -> friend.get("name")); // Act: delete reference persons.data.referenceDelete( john.uuid(), "hasFriend", - Reference.object(barbara)); + ObjectReference.object(barbara)); // Assert johnWithFriends = persons.query.fetchObjectById(john.uuid(), @@ -202,8 +200,8 @@ public void testReferences_AddReplaceDelete() throws IOException { Assertions.assertThat(johnWithFriends).get() .as("friends after DELETE") - .extracting(ReadWeaviateObject::references).extracting("hasFriend") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .extracting(WeaviateObject::references).extracting("hasFriend") + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) .isEmpty(); } @@ -229,7 +227,7 @@ public void testReplace() throws IOException { Assertions.assertThat(replacedIvanhoe).get() .as("has ONLY year property") - .extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .doesNotContain(Map.entry("title", "ivanhoe")) .contains(Map.entry("year", 1819L)); } @@ -265,7 +263,7 @@ public void testUpdate() throws IOException { books.data.update(ivanhoe.uuid(), update -> update .properties(Map.of("year", 1819)) - .reference("writtenBy", Reference.objects(walter)) + .reference("writtenBy", ObjectReference.objects(walter)) .vectors(Vectors.of(vector))); // Assert @@ -279,21 +277,20 @@ public void testUpdate() throws IOException { .satisfies(book -> { Assertions.assertThat(book) .as("has both year and title property") - .extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .contains(Map.entry("title", "ivanhoe"), Map.entry("year", 1819L)); Assertions.assertThat(book) .as("has reference to Authors") - .extracting(ReadWeaviateObject::references, InstanceOfAssertFactories.MAP) - .extractingByKey("writtenBy", InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .extracting(WeaviateObject::references, InstanceOfAssertFactories.MAP) + .extractingByKey("writtenBy", InstanceOfAssertFactories.list(WeaviateObject.class)) .first() - .extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .contains(Map.entry("name", "walter scott")); Assertions.assertThat(book) .as("has a vector") - .extracting(ReadWeaviateObject::metadata) - .extracting(QueryMetadata::vectors) + .extracting(WeaviateObject::vectors) .returns(vector, Vectors::getDefaultSingle); }); } @@ -386,7 +383,7 @@ public void testReferenceAddMany() throws IOException { var alpha = airports.data.insert(Map.of()).uuid(); var goodburg = cities.data.insert(Map.of(), city -> city - .reference("hasAirports", Reference.uuids(alpha))); + .reference("hasAirports", ObjectReference.uuid(alpha))); // Act var newAirports = airports.data.insertMany(Map.of(), Map.of()); @@ -404,10 +401,10 @@ public void testReferenceAddMany() throws IOException { Assertions.assertThat(goodburgAirports).get() .as("Goodburg has 3 airports") - .extracting(ReadWeaviateObject::references) + .extracting(WeaviateObject::references) .extracting(references -> references.get("hasAirports"), - InstanceOfAssertFactories.list(ReadWeaviateObject.class)) - .extracting(ReadWeaviateObject::uuid) + InstanceOfAssertFactories.list(WeaviateObject.class)) + .extracting(WeaviateObject::uuid) .contains(alpha, bravo, charlie); } @@ -485,7 +482,7 @@ public void testDataTypes() throws IOException { // Assert Assertions.assertThat(got).get() - .extracting(ReadWeaviateObject::properties) + .extracting(WeaviateObject::properties) .asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class)) // Most of PhoneNumber fields are only present on read and are null on write. .usingRecursiveComparison() @@ -557,6 +554,6 @@ public void test_multiTenant() throws IOException { var inserted = emails.data.insert(Map.of("subject", "McDonald's Xmas Bonanza")); // Assert - Assertions.assertThat(inserted).returns(johndoe, WriteWeaviateObject::tenant); + Assertions.assertThat(inserted).returns(johndoe, WeaviateObject::tenant); } } diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index a5e0984ed..6095d91b4 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -17,10 +17,10 @@ import io.weaviate.client6.v1.api.collections.CollectionConfig; import io.weaviate.client6.v1.api.collections.GeoCoordinates; import io.weaviate.client6.v1.api.collections.PhoneNumber; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.client6.v1.api.collections.annotations.Property; import io.weaviate.client6.v1.api.collections.data.InsertManyResponse.InsertObject; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.containers.Container; @@ -358,7 +358,7 @@ public void test_partialScan() throws IOException { // Assert Assertions.assertThat(got).get() - .extracting(ReadWeaviateObject::properties) + .extracting(WeaviateObject::properties) .returns("Dystopia", Song::title) .returns(null, Song::album) .returns(0, Song::year) diff --git a/src/it/java/io/weaviate/integration/PaginationITest.java b/src/it/java/io/weaviate/integration/PaginationITest.java index b5e789e2b..be79cd1b2 100644 --- a/src/it/java/io/weaviate/integration/PaginationITest.java +++ b/src/it/java/io/weaviate/integration/PaginationITest.java @@ -18,10 +18,9 @@ import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.WeaviateException; import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.pagination.PaginationException; import io.weaviate.client6.v1.api.collections.query.Metadata; -import io.weaviate.client6.v1.api.collections.query.QueryMetadata; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.containers.Container; public class PaginationITest extends ConcurrentTest { @@ -46,8 +45,7 @@ public void testIterateAll() throws IOException { var allThings = things.paginate(); // Act: stream - var gotStream = allThings.stream() - .map(ReadWeaviateObject::metadata).map(QueryMetadata::uuid).toList(); + var gotStream = allThings.stream().map(WeaviateObject::uuid).toList(); // Assert Assertions.assertThat(gotStream) @@ -58,7 +56,7 @@ public void testIterateAll() throws IOException { // Act: for-loop var gotLoop = new ArrayList(); for (var thing : allThings) { - gotLoop.add(thing.metadata().uuid()); + gotLoop.add(thing.uuid()); } // Assert @@ -89,7 +87,7 @@ public void testResumePagination() throws IOException { // Iterate over first 5 objects String lastId = things.paginate(p -> p.pageSize(5)).stream() - .limit(5).map(thing -> thing.metadata().uuid()) + .limit(5).map(thing -> thing.uuid()) .reduce((prev, next) -> next).get(); // Act @@ -126,8 +124,7 @@ public void testWithQueryOptions() throws IOException { .as("uuid=" + thing.uuid()) .doesNotContainKey("dont_fetch"); - Assertions.assertThat(thing.metadata().creationTimeUnix()) - .isNotNull(); + Assertions.assertThat(thing.createdAt()).isNotNull(); } } diff --git a/src/it/java/io/weaviate/integration/ReferencesITest.java b/src/it/java/io/weaviate/integration/ReferencesITest.java index c8b51acc3..e5310ac28 100644 --- a/src/it/java/io/weaviate/integration/ReferencesITest.java +++ b/src/it/java/io/weaviate/integration/ReferencesITest.java @@ -13,9 +13,9 @@ import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.collections.Property; import io.weaviate.client6.v1.api.collections.ReferenceProperty; -import io.weaviate.client6.v1.api.collections.data.Reference; +import io.weaviate.client6.v1.api.collections.WeaviateObject; +import io.weaviate.client6.v1.api.collections.data.ObjectReference; import io.weaviate.client6.v1.api.collections.query.QueryReference; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.containers.Container; /** @@ -72,9 +72,9 @@ public void testReferences() throws IOException { var alex = artists.data.insert( Map.of("name", "Alex"), opt -> opt - .reference("hasAwards", Reference.uuids( + .reference("hasAwards", ObjectReference.uuids( grammy_1.uuid(), oscar_1.uuid())) - .reference("hasAwards", Reference.objects(grammy_2, oscar_2))); + .reference("hasAwards", ObjectReference.objects(grammy_2, oscar_2))); // Act: add one more reference var nsMovies = ns("Movies"); @@ -99,9 +99,9 @@ public void testReferences() throws IOException { .as("Artists: fetch by id including hasAwards references") // Cast references to Map> - .extracting(ReadWeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) + .extracting(WeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) .as("hasAwards object reference").extractingByKey("hasAwards") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) .extracting(object -> object.uuid()) .containsOnly( @@ -146,12 +146,12 @@ public void testNestedReferences() throws IOException { var musicAcademy = academies.data.insert(Map.of("ceo", "Harvy Mason")); var grammy_1 = grammies.data.insert(Map.of(), - opt -> opt.reference("presentedBy", Reference.objects(musicAcademy))); + opt -> opt.reference("presentedBy", ObjectReference.objects(musicAcademy))); var alex = artists.data.insert( Map.of("name", "Alex"), opt -> opt - .reference("hasAwards", Reference.objects(grammy_1))); + .reference("hasAwards", ObjectReference.objects(grammy_1))); // Assert: fetch nested references var gotAlex = artists.query.fetchObjectById(alex.uuid(), @@ -166,19 +166,19 @@ public void testNestedReferences() throws IOException { .as("Artists: fetch by id including nested references") // Cast references to Map> - .extracting(ReadWeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) + .extracting(WeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) .as("hasAwards object reference").extractingByKey("hasAwards") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) .hasSize(1).allSatisfy(award -> Assertions.assertThat(award) .returns(grammy_1.uuid(), grammy -> grammy.uuid()) // Cast references to Map> - .extracting(ReadWeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) + .extracting(WeaviateObject::references, InstanceOfAssertFactories.map(String.class, List.class)) .as("presentedBy object reference").extractingByKey("presentedBy") - .asInstanceOf(InstanceOfAssertFactories.list(ReadWeaviateObject.class)) + .asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class)) - .hasSize(1).extracting(ReadWeaviateObject::properties) + .hasSize(1).extracting(WeaviateObject::properties) .allSatisfy(properties -> Assertions.assertThat(properties) .asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class)) .containsEntry("ceo", "Harvy Mason"))); diff --git a/src/it/java/io/weaviate/integration/SearchITest.java b/src/it/java/io/weaviate/integration/SearchITest.java index d37a6718c..35f0aa30d 100644 --- a/src/it/java/io/weaviate/integration/SearchITest.java +++ b/src/it/java/io/weaviate/integration/SearchITest.java @@ -27,18 +27,15 @@ import io.weaviate.client6.v1.api.collections.Reranker; import io.weaviate.client6.v1.api.collections.VectorConfig; import io.weaviate.client6.v1.api.collections.Vectors; -import io.weaviate.client6.v1.api.collections.WeaviateMetadata; -import io.weaviate.client6.v1.api.collections.data.Reference; -import io.weaviate.client6.v1.api.collections.data.WriteWeaviateObject; +import io.weaviate.client6.v1.api.collections.WeaviateObject; +import io.weaviate.client6.v1.api.collections.data.ObjectReference; import io.weaviate.client6.v1.api.collections.generate.GenerativeObject; import io.weaviate.client6.v1.api.collections.generate.TaskOutput; import io.weaviate.client6.v1.api.collections.generative.DummyGenerative; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.client6.v1.api.collections.query.GroupBy; import io.weaviate.client6.v1.api.collections.query.Metadata; -import io.weaviate.client6.v1.api.collections.query.QueryMetadata; import io.weaviate.client6.v1.api.collections.query.QueryResponseGroup; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.client6.v1.api.collections.query.Rerank; import io.weaviate.client6.v1.api.collections.query.SortBy; import io.weaviate.client6.v1.api.collections.query.Target; @@ -91,7 +88,7 @@ public void testNearVector() { Assertions.assertThat(result.objects()).hasSize(3); float maxDistance = Collections.max(result.objects(), - Comparator.comparing(obj -> obj.metadata().distance())).metadata().distance(); + Comparator.comparing(obj -> obj.queryMetadata().distance())).queryMetadata().distance(); Assertions.assertThat(maxDistance).isLessThanOrEqualTo(2f); } @@ -172,7 +169,7 @@ public void testNearText() throws IOException { .returnProperties("title")); Assertions.assertThat(result.objects()).hasSize(2) - .extracting(ReadWeaviateObject::properties).allSatisfy( + .extracting(WeaviateObject::properties).allSatisfy( properties -> Assertions.assertThat(properties) .allSatisfy((_k, v) -> Assertions.assertThat((String) v).contains("Jungle"))); } @@ -200,9 +197,9 @@ public void testNearText_groupBy() throws IOException { var songs = client.collections.use(nsSongs); songs.data.insert(Map.of("title", "Yellow Submarine"), - s -> s.reference("performedBy", Reference.objects(beatles))); + s -> s.reference("performedBy", ObjectReference.objects(beatles))); songs.data.insert(Map.of("title", "Run Through The Jungle"), - s -> s.reference("performedBy", Reference.objects(ccr))); + s -> s.reference("performedBy", ObjectReference.objects(ccr))); var result = songs.query.nearText("nature", opt -> opt.returnProperties("title"), @@ -235,7 +232,7 @@ public void testNearImage() throws IOException { opt -> opt.returnProperties("breed")); Assertions.assertThat(got.objects()).hasSize(1).first() - .extracting(ReadWeaviateObject::properties, InstanceOfAssertFactories.MAP) + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP) .extractingByKey("breed").isEqualTo("ragdoll"); } @@ -265,7 +262,7 @@ public void testFetchObjectsWithFilters() throws IOException { Filter.property("size").lt(6))))); Assertions.assertThat(got.objects()) - .extracting(hat -> hat.metadata().uuid()) + .extracting(WeaviateObject::uuid) .containsOnly( redHat.uuid(), greenHat.uuid(), @@ -294,7 +291,7 @@ public void testFetchObjectsWithSort() throws Exception { Assertions.assertThat(asc.objects()) .as("value asc") .hasSize(3) - .extracting(ReadWeaviateObject::properties) + .extracting(WeaviateObject::properties) .extracting(object -> object.get("value")) .containsExactly(1L, 2L, 3L); @@ -305,7 +302,7 @@ public void testFetchObjectsWithSort() throws Exception { Assertions.assertThat(desc.objects()) .as("value desc") .hasSize(3) - .extracting(ReadWeaviateObject::properties) + .extracting(WeaviateObject::properties) .extracting(object -> object.get("value")) .containsExactly(3L, 2L, 1L); } @@ -331,7 +328,7 @@ public void testBm25() throws IOException, InterruptedException, ExecutionExcept Assertions.assertThat(dollarWorlds.objects()) .hasSize(1) - .extracting(ReadWeaviateObject::metadata).extracting(QueryMetadata::uuid) + .extracting(WeaviateObject::uuid) .containsOnly(want.uuid()); } @@ -363,7 +360,7 @@ public void testBm25_async() throws Exception, InterruptedException, ExecutionEx Assertions.assertThat(dollarWorlds.objects()) .hasSize(1) - .extracting(ReadWeaviateObject::metadata).extracting(QueryMetadata::uuid) + .extracting(WeaviateObject::uuid) .containsOnly(want.uuid()); } } @@ -393,7 +390,7 @@ public void testNearObject() throws IOException { // Assert Assertions.assertThat(terrestrial.objects()) .hasSize(1) - .extracting(ReadWeaviateObject::metadata).extracting(WeaviateMetadata::uuid) + .extracting(WeaviateObject::uuid) .containsOnly(lion.uuid()); } @@ -420,13 +417,13 @@ public void testHybrid() throws IOException { // Assert Assertions.assertThat(winterSport.objects()) .hasSize(1) - .extracting(ReadWeaviateObject::metadata).extracting(WeaviateMetadata::uuid) + .extracting(WeaviateObject::uuid) .containsOnly(skiing.uuid()); var first = winterSport.objects().get(0); - Assertions.assertThat(first.metadata().score()) + Assertions.assertThat(first.queryMetadata().score()) .as("metadata::score").isNotNull(); - Assertions.assertThat(first.metadata().explainScore()) + Assertions.assertThat(first.queryMetadata().explainScore()) .as("metadata::explainScore").isNotNull(); } @@ -490,7 +487,7 @@ public void test_includeVectors() throws IOException { // Assert Assertions.assertThat(got).get() - .extracting(ReadWeaviateObject::vectors) + .extracting(WeaviateObject::vectors) .returns(true, v -> v.contains("v1")) .returns(true, v -> v.contains("v2")) .returns(false, v -> v.contains("v3")); @@ -517,25 +514,23 @@ public void testMetadataAll() throws IOException { .returnMetadata(Metadata.ALL)); // Assert - var metadataHybrid = Assertions.assertThat(gotHybrid.objects()) - .hasSize(1) - .extracting(ReadWeaviateObject::metadata) - .first().actual(); + var hybridObject = Assertions.assertThat(gotHybrid.objects()) + .hasSize(1).first().actual(); + var hybridMetadata = hybridObject.queryMetadata(); - Assertions.assertThat(metadataHybrid.uuid()).as("uuid").isNotNull().isEqualTo(frisbee.uuid()); - Assertions.assertThat(metadataHybrid.creationTimeUnix()).as("creationTimeUnix").isNotNull(); - Assertions.assertThat(metadataHybrid.lastUpdateTimeUnix()).as("lastUpdateTimeUnix").isNotNull(); - Assertions.assertThat(metadataHybrid.score()).as("score").isNotNull(); - Assertions.assertThat(metadataHybrid.explainScore()).as("explainScore").isNotNull().isNotEqualTo(""); + Assertions.assertThat(hybridObject.uuid()).as("uuid").isNotNull().isEqualTo(frisbee.uuid()); + Assertions.assertThat(hybridObject.createdAt()).as("createdAt").isNotNull(); + Assertions.assertThat(hybridObject.lastUpdatedAt()).as("lastUpdateTimeUnix").isNotNull(); + Assertions.assertThat(hybridMetadata.score()).as("score").isNotNull(); + Assertions.assertThat(hybridMetadata.explainScore()).as("explainScore").isNotNull().isNotEqualTo(""); - var metadataNearText = Assertions.assertThat(gotNearText.objects()) - .hasSize(1) - .extracting(ReadWeaviateObject::metadata) - .first().actual(); + var nearTextObject = Assertions.assertThat(gotNearText.objects()) + .hasSize(1).first().actual(); + var metadataNearText = nearTextObject.queryMetadata(); - Assertions.assertThat(metadataNearText.uuid()).as("uuid").isNotNull().isEqualTo(frisbee.uuid()); - Assertions.assertThat(metadataNearText.creationTimeUnix()).as("creationTimeUnix").isNotNull(); - Assertions.assertThat(metadataNearText.lastUpdateTimeUnix()).as("lastUpdateTimeUnix").isNotNull(); + Assertions.assertThat(nearTextObject.uuid()).as("uuid").isNotNull().isEqualTo(frisbee.uuid()); + Assertions.assertThat(nearTextObject.createdAt()).as("createdAt").isNotNull(); + Assertions.assertThat(nearTextObject.lastUpdatedAt()).as("lastUpdateTimeUnix").isNotNull(); Assertions.assertThat(metadataNearText.distance()).as("distance").isNotNull(); Assertions.assertThat(metadataNearText.certainty()).as("certainty").isNotNull(); } @@ -558,7 +553,7 @@ public void testNearVector_targetVectors() throws IOException { Vectors.of("v2d", new float[][] { { 1, 2, 3 }, { 1, 2, 3 } }))); var thing456 = things.data.insertMany(List.of( - WriteWeaviateObject.of(thing -> thing + WeaviateObject.of(thing -> thing .vectors( Vectors.of("v1d", new float[] { 4, 5, 6 }), Vectors.of("v2d", new float[][] { { 4, 5, 6 }, { 4, 5, 6 } }))))); @@ -570,7 +565,7 @@ public void testNearVector_targetVectors() throws IOException { q -> q.limit(1)); Assertions.assertThat(got123.objects()) .as("search v1d") - .hasSize(1).extracting(ReadWeaviateObject::uuid) + .hasSize(1).extracting(WeaviateObject::uuid) .containsExactly(thing123.uuid()); var got456 = things.query.nearVector( @@ -578,7 +573,7 @@ public void testNearVector_targetVectors() throws IOException { q -> q.limit(1)); Assertions.assertThat(got456.objects()) .as("search v2d") - .hasSize(1).extracting(ReadWeaviateObject::uuid) + .hasSize(1).extracting(WeaviateObject::uuid) .containsExactly(thing456.uuids().get(0)); } @@ -760,7 +755,7 @@ public void test_maxGrpcMessageSize() throws Exception { .vectorConfig(VectorConfig.selfProvided())); final var vector = randomVector(5000, -.01f, .01f); - final WriteWeaviateObject> hugeObject = WriteWeaviateObject.of( + final WeaviateObject> hugeObject = WeaviateObject.of( obj -> obj.vectors(Vectors.of(vector))); Assertions.assertThatThrownBy(() -> { diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/ObjectMetadata.java b/src/main/java/io/weaviate/client6/v1/api/collections/ObjectMetadata.java deleted file mode 100644 index e467644c7..000000000 --- a/src/main/java/io/weaviate/client6/v1/api/collections/ObjectMetadata.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.weaviate.client6.v1.api.collections; - -import java.util.UUID; -import java.util.function.Function; - -import com.google.gson.annotations.SerializedName; - -import io.weaviate.client6.v1.internal.ObjectBuilder; - -public record ObjectMetadata( - @SerializedName("id") String uuid, - @SerializedName("vectors") Vectors vectors, - @SerializedName("creationTimeUnix") Long createdAt, - @SerializedName("lastUpdateTimeUnix") Long lastUpdatedAt) implements WeaviateMetadata { - - public ObjectMetadata(Builder builder) { - this(builder.uuid, builder.vectors, null, null); - } - - public static ObjectMetadata of() { - return of(ObjectBuilder.identity()); - } - - public static ObjectMetadata of(Function> fn) { - return fn.apply(new Builder()).build(); - } - - public static class Builder implements ObjectBuilder { - private String uuid = UUID.randomUUID().toString(); - private Vectors vectors; - - /** Assign a custom UUID for the object. */ - public Builder uuid(UUID uuid) { - return uuid(uuid.toString()); - } - - /** Assign a custom UUID for the object. */ - public Builder uuid(String uuid) { - this.uuid = uuid; - return this; - } - - /** Attach custom vectors to the object.. */ - public Builder vectors(Vectors... vectors) { - this.vectors = new Vectors(vectors); - return this; - } - - @Override - public ObjectMetadata build() { - return new ObjectMetadata(this); - } - } -} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/Reference.java b/src/main/java/io/weaviate/client6/v1/api/collections/Reference.java new file mode 100644 index 000000000..09576f08a --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/collections/Reference.java @@ -0,0 +1,41 @@ +package io.weaviate.client6.v1.api.collections; + +import java.util.Map; + +import io.weaviate.client6.v1.api.collections.data.ObjectReference; + +public interface Reference { + /** UUID of the reference object. */ + String uuid(); + + /** Name of the collection the reference belongs to. */ + String collection(); + + /** + * Cast {@code this} into an instance of {@link WeaviateObject>}. Useful when working with references retrieved in a query. + * + *
{@code
+   *  var metalSongs = songs.query.fetchObjects(q -> q
+   *    .filters(Filter.property("genres").containsAll("metal")
+   *    .returnReferences(QueryReference.multi("performedBy"));
+   *
+   *  metalSongs.objects().forEach(song -> {
+   *    var songName = song.properties().get("name");
+   *    song.references().forEach(ref -> {
+   *      var artistName = ref.asWeaviateObject().properties().get("artistName");
+   *      System.out.printf("%s is performed by %s", songName, artistName);
+   *    });
+   *  });
+   * }
+ * + *

+ * Only call this method on objects returned from methods under {@code .query} + * namespace, as insert-references do not implement this interface. + * + * @throws IllegalStateException if reference object is an instance of + * {@link ObjectReference}. See usage guidelines + * above. + */ + WeaviateObject> asWeaviateObject(); +} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateMetadata.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateMetadata.java deleted file mode 100644 index a4b8cc05a..000000000 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateMetadata.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.weaviate.client6.v1.api.collections; - -public interface WeaviateMetadata { - /** Object's UUID. */ - String uuid(); - - /** Object's associated vector embeddings. */ - Vectors vectors(); -} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateObject.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateObject.java index dedc38849..7faf0e20b 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateObject.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateObject.java @@ -1,9 +1,209 @@ package io.weaviate.client6.v1.api.collections; -public interface WeaviateObject { - String uuid(); +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; - String collection(); +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.annotations.SerializedName; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; - Vectors vectors(); +import io.weaviate.client6.v1.api.collections.data.ObjectReference; +import io.weaviate.client6.v1.api.collections.query.QueryMetadata; +import io.weaviate.client6.v1.internal.ObjectBuilder; + +public record WeaviateObject( + @SerializedName("id") String uuid, + @SerializedName("class") String collection, + @SerializedName("tenant") String tenant, + @SerializedName("properties") PropertiesT properties, + @SerializedName("vectors") Vectors vectors, + @SerializedName("creationTimeUnix") Long createdAt, + @SerializedName("lastUpdateTimeUnix") Long lastUpdatedAt, + + QueryMetadata queryMetadata, + Map> references) implements Reference { + + @SuppressWarnings("unchecked") + @Override + public WeaviateObject> asWeaviateObject() { + return (WeaviateObject>) this; + } + + public static WeaviateObject of( + Function, ObjectBuilder>> fn) { + return fn.apply(new Builder<>()).build(); + } + + public WeaviateObject(Builder builder) { + this( + builder.uuid, + null, // collection name is derived from CollectionHandle + builder.tenant, // tenant MAY be derived from CollectionHandle + builder.properties, + builder.vectors, + null, // createdAt is read-only + null, // lastUpdatedAt is read-only + null, // queryMetadata is read-only + builder.references); + } + + public static class Builder implements ObjectBuilder> { + /** + * The server should be providing default UUIDs, but it does not do that + * during batch inserts and we have to provide our own. + * Rather than make this behaviour special to {@code insertMany}, we are going + * to provide a fallback UUID "globally". + */ + private String uuid = UUID.randomUUID().toString(); + private String tenant; + private PropertiesT properties; + private Vectors vectors; + private Map> references = new HashMap<>(); + + public Builder uuid(String uuid) { + this.uuid = uuid; + return this; + } + + public Builder tenant(String tenant) { + this.tenant = tenant; + return this; + } + + public Builder properties(PropertiesT properties) { + this.properties = properties; + return this; + } + + /** + * Add a reference. Calls to {@link #reference} can be chained + * to add multiple references. + */ + public Builder reference(String property, Reference... references) { + for (var ref : references) { + addReference(property, ref); + } + return this; + } + + public Builder references(Map> references) { + this.references = references; + return this; + } + + private void addReference(String property, Reference reference) { + if (!references.containsKey(property)) { + references.put(property, new ArrayList<>()); + } + references.get(property).add(reference); + } + + public Builder vectors(Vectors... vectors) { + if (this.vectors == null) { + this.vectors = vectors.length == 1 ? vectors[0] : new Vectors(vectors); + } else { + this.vectors = this.vectors.withVectors(vectors); + } + return this; + } + + @Override + public WeaviateObject build() { + return new WeaviateObject<>(this); + } + } + + public static enum CustomTypeAdapterFactory implements TypeAdapterFactory { + INSTANCE; + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken typeToken) { + var type = typeToken.getType(); + var rawType = typeToken.getRawType(); + if (rawType != WeaviateObject.class || + !(type instanceof ParameterizedType parameterized) + || parameterized.getActualTypeArguments().length != 1) { + return null; + } + + var typeParams = parameterized.getActualTypeArguments(); + final var propertiesType = typeParams[0]; + + final var delegate = (TypeAdapter>) gson + .getDelegateAdapter(this, typeToken); + final var propertiesAdapter = (TypeAdapter) gson.getAdapter(TypeToken.get(propertiesType)); + final var referencesAdapter = gson.getAdapter(ObjectReference.class); + + return (TypeAdapter) new TypeAdapter>() { + + @Override + public void write(JsonWriter out, WeaviateObject value) throws IOException { + var json = delegate.toJsonTree(value).getAsJsonObject(); + var properties = value.properties() != null + ? propertiesAdapter.toJsonTree(value.properties()).getAsJsonObject() + : new JsonObject(); + + if (value.references() != null && !value.references().isEmpty()) { + for (var refEntry : value.references().entrySet()) { + var beacons = new JsonArray(); + for (var reference : refEntry.getValue()) { + var beacon = referencesAdapter.toJsonTree((ObjectReference) reference); + beacons.add(beacon); + } + properties.add(refEntry.getKey(), beacons); + } + } + + json.add("properties", properties); + json.remove("references"); + Streams.write(json, out); + } + + @Override + public WeaviateObject read(JsonReader in) throws IOException { + var json = JsonParser.parseReader(in).getAsJsonObject(); + + var jsonProperties = json.get("properties").getAsJsonObject(); + var objectProperties = new JsonObject(); + var objectReferences = new JsonObject(); + + for (var property : jsonProperties.entrySet()) { + var value = property.getValue(); + + if (value.isJsonArray()) { + var array = value.getAsJsonArray(); + var first = array.get(0); + var isReference = first.isJsonObject() && first.getAsJsonObject().has("beacon"); + + if (isReference) { + objectReferences.add(property.getKey(), value); + continue; + } + } + + objectProperties.add(property.getKey(), value); + } + + json.add("references", objectReferences); + json.add("properties", objectProperties); + return delegate.fromJsonTree(json); + } + }.nullSafe(); + } + } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/BatchReference.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/BatchReference.java index 9854a57bc..a83652be5 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/BatchReference.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/BatchReference.java @@ -9,23 +9,23 @@ import io.weaviate.client6.v1.api.collections.WeaviateObject; -public record BatchReference(String fromCollection, String fromProperty, String fromUuid, Reference reference) { +public record BatchReference(String fromCollection, String fromProperty, String fromUuid, ObjectReference reference) { - public static BatchReference[] objects(WeaviateObject fromObject, String fromProperty, - WeaviateObject... toObjects) { + public static BatchReference[] objects(WeaviateObject fromObject, String fromProperty, + WeaviateObject... toObjects) { return Arrays.stream(toObjects) .map(to -> new BatchReference( fromObject.collection(), fromProperty, fromObject.uuid(), - Reference.object(to))) + ObjectReference.object(to))) .toArray(BatchReference[]::new); } - public static BatchReference[] uuids(WeaviateObject fromObject, String fromProperty, + public static BatchReference[] uuids(WeaviateObject fromObject, String fromProperty, String... toUuids) { return Arrays.stream(toUuids) .map(to -> new BatchReference( fromObject.collection(), fromProperty, fromObject.uuid(), - Reference.uuids(to))) + ObjectReference.uuid(to))) .toArray(BatchReference[]::new); } @@ -36,12 +36,10 @@ public void write(JsonWriter out, BatchReference value) throws IOException { out.beginObject(); out.name("from"); - out.value(Reference.toBeacon(value.fromCollection, value.fromProperty, value.fromUuid)); + out.value(ObjectReference.toBeacon(value.fromCollection, value.fromProperty, value.fromUuid)); out.name("to"); - out.value(Reference.toBeacon(value.reference.collection(), value.reference.uuids().get(0))); - - // TODO: add tenant + out.value(ObjectReference.toBeacon(value.reference.collection(), value.reference.uuid())); out.endObject(); } @@ -51,7 +49,7 @@ public BatchReference read(JsonReader in) throws IOException { String fromCollection = null; String fromProperty = null; String fromUuid = null; - Reference toReference = null; + ObjectReference toReference = null; in.beginObject(); while (in.hasNext()) { @@ -81,23 +79,9 @@ public BatchReference read(JsonReader in) throws IOException { } else { id = beacon; } - toReference = new Reference(collection, id); + toReference = new ObjectReference(collection, id); break; } - - // case "tenant": - // switch (in.peek()) { - // case STRING: - // in.nextString(); - // case NULL: - // in.nextNull(); - // default: - // // We don't expect anything else - // } - // System.out.println("processed tenant"); - // break; - // default: - // in.skipValue(); } } in.endObject(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java index 1e71855d0..2fff8681a 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java @@ -46,7 +46,7 @@ public static Rpc new DeleteManyResponse.DeletedObject( - ByteStringUtil.decodeUuid(obj.getUuid()).toString(), + ByteStringUtil.decodeUuid(obj.getUuid()), obj.getSuccessful(), obj.getError())) .toList(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java index 843bdbb02..11df4e8b9 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java @@ -10,6 +10,7 @@ import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; import io.weaviate.client6.v1.api.collections.GeoCoordinates; import io.weaviate.client6.v1.api.collections.PhoneNumber; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.MapUtil; import io.weaviate.client6.v1.internal.grpc.ByteStringUtil; import io.weaviate.client6.v1.internal.grpc.Rpc; @@ -20,10 +21,10 @@ import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateProtoBatch; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; -public record InsertManyRequest(List> objects) { +public record InsertManyRequest(List> objects) { @SafeVarargs - public InsertManyRequest(WriteWeaviateObject... objects) { + public InsertManyRequest(WeaviateObject... objects) { this(Arrays.asList(objects)); } @@ -31,13 +32,13 @@ public InsertManyRequest(WriteWeaviateObject... objects) { @SafeVarargs public static final InsertManyRequest of(PropertiesT... properties) { var objects = Arrays.stream(properties) - .map(p -> (WriteWeaviateObject) WriteWeaviateObject.of(obj -> obj.properties(p))) + .map(p -> (WeaviateObject) WeaviateObject.of(obj -> obj.properties(p))) .toList(); return new InsertManyRequest<>(objects); } public static Rpc, WeaviateProtoBatch.BatchObjectsRequest, InsertManyResponse, WeaviateProtoBatch.BatchObjectsReply> rpc( - List> insertObjects, + List> insertObjects, CollectionDescriptor collection, CollectionHandleDefaults defaults) { return Rpc.insert( @@ -92,7 +93,7 @@ public static Rpc, WeaviateProtoBat } public static void buildObject(WeaviateProtoBatch.BatchObject.Builder object, - WriteWeaviateObject insert, + WeaviateObject insert, CollectionDescriptor collection, CollectionHandleDefaults defaults) { object.setCollection(collection.collectionName()); @@ -135,11 +136,13 @@ public static void buildObject(WeaviateProtoBatch.BatchObject.Builder object // is single- or multi-target? for (var ref : references) { if (ref.collection() == null) { - singleRef.add(WeaviateProtoBatch.BatchObject.SingleTargetRefProps.newBuilder().addAllUuids(ref.uuids()) + singleRef.add(WeaviateProtoBatch.BatchObject.SingleTargetRefProps.newBuilder() + .addUuids(ref.uuid()) .setPropName(entry.getKey()).build()); } else { multiRef.add(WeaviateProtoBatch.BatchObject.MultiTargetRefProps.newBuilder() - .setTargetCollection(ref.collection()).addAllUuids(ref.uuids()).setPropName(entry.getKey()).build()); + .setTargetCollection(ref.collection()).addUuids(ref.uuid()) + .setPropName(entry.getKey()).build()); } } }); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertObjectRequest.java index cf992eba7..8588eb760 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertObjectRequest.java @@ -7,21 +7,22 @@ import com.google.gson.reflect.TypeToken; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.json.JSON; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record InsertObjectRequest(WriteWeaviateObject object) { +public record InsertObjectRequest(WeaviateObject object) { @SuppressWarnings("unchecked") - public static final Endpoint, WriteWeaviateObject> endpoint( + public static final Endpoint, WeaviateObject> endpoint( CollectionDescriptor collection, CollectionHandleDefaults defaults) { - final var typeToken = (TypeToken>) TypeToken - .getParameterized(WriteWeaviateObject.class, collection.typeToken().getType()); + final var typeToken = (TypeToken>) TypeToken + .getParameterized(WeaviateObject.class, collection.typeToken().getType()); return new SimpleEndpoint<>( request -> "POST", @@ -30,7 +31,7 @@ public static final Endpoint, Wri ? Map.of("consistency_level", defaults.consistencyLevel()) : Collections.emptyMap(), request -> JSON.serialize( - new WriteWeaviateObject<>( + new WeaviateObject<>( request.object.uuid(), collection.collectionName(), defaults.tenant(), @@ -38,6 +39,7 @@ public static final Endpoint, Wri request.object.vectors(), request.object.createdAt(), request.object.lastUpdatedAt(), + null, // no queryMetadata no insert request.object.references()), typeToken), (statusCode, response) -> JSON.deserialize(response, typeToken)); @@ -49,7 +51,7 @@ static InsertObjectRequest of(PropertiesT properties) static InsertObjectRequest of( PropertiesT properties, - Function, ObjectBuilder>> fn) { - return new InsertObjectRequest<>(WriteWeaviateObject.of(ObjectBuilder.partial(fn, b -> b.properties(properties)))); + Function, ObjectBuilder>> fn) { + return new InsertObjectRequest<>(WeaviateObject.of(ObjectBuilder.partial(fn, b -> b.properties(properties)))); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ObjectReference.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ObjectReference.java new file mode 100644 index 000000000..bb6a0f27e --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ObjectReference.java @@ -0,0 +1,125 @@ +package io.weaviate.client6.v1.api.collections.data; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import io.weaviate.client6.v1.api.collections.Reference; +import io.weaviate.client6.v1.api.collections.WeaviateObject; + +public record ObjectReference(String collection, String uuid) implements Reference { + + @Override + public WeaviateObject> asWeaviateObject() { + throw new IllegalStateException("cannot convert to WeaviateObject"); + } + + /** + * Create reference to a single object by UUID. + *

+ * Weaviate will search each of the existing collections to identify + * the objects before inserting the references, so this may include + * some performance overhead. + */ + public static ObjectReference uuid(String uuid) { + return new ObjectReference(null, uuid); + } + + /** + * Create reference to objects by their UUIDs. + *

+ * Weaviate will search each of the existing collections to identify + * the objects before inserting the references, so this may include + * some performance overhead. + */ + public static ObjectReference[] uuids(String... uuids) { + return Arrays.stream(uuids) + .map(ObjectReference::uuid) + .toArray(ObjectReference[]::new); + } + + /** Create references to single {@link WeaviateObject}. */ + public static ObjectReference object(WeaviateObject object) { + return new ObjectReference(object.collection(), object.uuid()); + } + + /** Create references to multiple {@link WeaviateObject}. */ + public static ObjectReference[] objects(WeaviateObject... objects) { + return Arrays.stream(objects) + .map(o -> new ObjectReference(o.collection(), o.uuid())) + .toArray(ObjectReference[]::new); + } + + /** Create a reference to an single object in a collection by its UUID. */ + public static ObjectReference collection(String collection, String uuid) { + return new ObjectReference(collection, uuid); + } + + /** Create references to objects in a collection by their UUIDs. */ + public static ObjectReference[] collection(String collection, String... uuids) { + return Arrays.stream(uuids) + .map(uuid -> new ObjectReference(collection, uuid)) + .toArray(ObjectReference[]::new); + } + + public static String toBeacon(String collection, String uuid) { + return toBeacon(collection, null, uuid); + } + + public static String toBeacon(String collection, String property, String uuid) { + var beacon = "weaviate://localhost"; + if (collection != null) { + beacon += "/" + collection; + } + beacon += "/" + uuid; + if (property != null) { + beacon += "/" + property; + } + return beacon; + } + + public static final TypeAdapter TYPE_ADAPTER = new TypeAdapter() { + + @Override + public void write(JsonWriter out, ObjectReference value) throws IOException { + out.beginObject(); + out.name("beacon"); + out.value(toBeacon(value.collection(), value.uuid())); + out.endObject(); + } + + @Override + public ObjectReference read(JsonReader in) throws IOException { + String collection = null; + String id = null; + + in.beginObject(); + in.nextName(); // expect "beacon"? + var beacon = in.nextString(); + + // Skip to the end of the object. There's going to be the "href" + // key too, which is irrelevant for us. + while (in.peek() != JsonToken.END_OBJECT) { + in.skipValue(); + } + in.endObject(); + + beacon = beacon.replaceFirst("weaviate://localhost/", ""); + if (beacon.contains("/")) { + var parts = beacon.split("/"); + collection = parts[0]; + id = parts[1]; + } else { + id = beacon; + } + + return new ObjectReference(collection, id); + } + + }.nullSafe(); +} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/Reference.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/Reference.java deleted file mode 100644 index 097478788..000000000 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/Reference.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.weaviate.client6.v1.api.collections.data; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; - -import io.weaviate.client6.v1.api.collections.WeaviateObject; - -public record Reference(String collection, List uuids) { - - public Reference(String collection, String uuid) { - this(collection, List.of(uuid)); - } - - /** - * Create reference to objects by their UUIDs. - *

- * Weaviate will search each of the existing collections to identify - * the objects before inserting the references, so this may include - * some performance overhead. - */ - public static Reference uuids(String... uuids) { - return new Reference(null, Arrays.asList(uuids)); - } - - /** Create references to single {@link WeaviateObject}. */ - public static Reference object(WeaviateObject object) { - return new Reference(object.collection(), object.uuid()); - } - - /** Create references to multiple {@link WeaviateObject}. */ - public static Reference[] objects(WeaviateObject... objects) { - return Arrays.stream(objects) - .map(o -> new Reference(o.collection(), o.uuid())) - .toArray(Reference[]::new); - } - - /** Create references to objects in a collection by their UUIDs. */ - public static Reference collection(String collection, String... uuids) { - return new Reference(collection, Arrays.asList(uuids)); - } - - public static String toBeacon(String collection, String uuid) { - return toBeacon(collection, null, uuid); - } - - public static String toBeacon(String collection, String property, String uuid) { - var beacon = "weaviate://localhost"; - if (collection != null) { - beacon += "/" + collection; - } - beacon += "/" + uuid; - if (property != null) { - beacon += "/" + property; - } - return beacon; - } - - public static final TypeAdapter TYPE_ADAPTER = new TypeAdapter() { - - @Override - public void write(JsonWriter out, Reference value) throws IOException { - for (var uuid : value.uuids()) { - out.beginObject(); - out.name("beacon"); - out.value(toBeacon(value.collection(), uuid)); - out.endObject(); - } - } - - @Override - public Reference read(JsonReader in) throws IOException { - String collection = null; - String id = null; - - in.beginObject(); - in.nextName(); // expect "beacon"? - var beacon = in.nextString(); - - // Skip to the end of the object. There's going to be the "href" - // key too, which is irrelevant for us. - while (in.peek() != JsonToken.END_OBJECT) { - in.skipValue(); - } - in.endObject(); - - beacon = beacon.replaceFirst("weaviate://localhost/", ""); - if (beacon.contains("/")) { - var parts = beacon.split("/"); - collection = parts[0]; - id = parts[1]; - } else { - id = beacon; - } - - return new Reference(collection, id); - } - - }.nullSafe(); -} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java index 00a04c654..174e868c2 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java @@ -6,7 +6,7 @@ import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record ReferenceAddRequest(String fromUuid, String fromProperty, Reference reference) { +public record ReferenceAddRequest(String fromUuid, String fromProperty, ObjectReference reference) { public static final Endpoint endpoint( CollectionDescriptor descriptor, diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java index 9144f2b2f..d17336bb7 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java @@ -6,7 +6,7 @@ import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record ReferenceDeleteRequest(String fromUuid, String fromProperty, Reference reference) { +public record ReferenceDeleteRequest(String fromUuid, String fromProperty, ObjectReference reference) { public static final Endpoint endpoint( CollectionDescriptor descriptor, diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java index 3bf7b1e30..f68876ee7 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java @@ -8,7 +8,7 @@ import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record ReferenceReplaceRequest(String fromUuid, String fromProperty, Reference reference) { +public record ReferenceReplaceRequest(String fromUuid, String fromProperty, ObjectReference reference) { public static final Endpoint endpoint( CollectionDescriptor descriptor, diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java index d3d1ec31f..13a1afacb 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java @@ -8,19 +8,20 @@ import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.json.JSON; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record ReplaceObjectRequest(WriteWeaviateObject object) { +public record ReplaceObjectRequest(WeaviateObject object) { static final Endpoint, Void> endpoint( CollectionDescriptor collection, CollectionHandleDefaults defaults) { - final var typeToken = TypeToken.getParameterized(WriteWeaviateObject.class, collection.typeToken().getType()); + final var typeToken = TypeToken.getParameterized(WeaviateObject.class, collection.typeToken().getType()); return SimpleEndpoint.sideEffect( request -> "PUT", @@ -29,7 +30,7 @@ static final Endpoint, Void> end ? Map.of("consistency_level", defaults.consistencyLevel()) : Collections.emptyMap(), request -> JSON.serialize( - new WriteWeaviateObject<>( + new WeaviateObject<>( request.object.uuid(), collection.collectionName(), defaults.tenant(), @@ -37,6 +38,7 @@ static final Endpoint, Void> end request.object.vectors(), request.object.createdAt(), request.object.lastUpdatedAt(), + null, request.object.references()), typeToken)); } @@ -52,7 +54,7 @@ public ReplaceObjectRequest(Builder builder) { } public static class Builder implements ObjectBuilder> { - private final WriteWeaviateObject.Builder object = new WriteWeaviateObject.Builder<>(); + private final WeaviateObject.Builder object = new WeaviateObject.Builder<>(); public Builder(String uuid) { this.object.uuid(uuid); @@ -68,7 +70,7 @@ public Builder vectors(Vectors... vectors) { return this; } - public Builder reference(String property, Reference... references) { + public Builder reference(String property, ObjectReference... references) { this.object.reference(property, references); return this; } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java index 3368468a7..6157a1cc8 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java @@ -8,19 +8,20 @@ import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.json.JSON; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record UpdateObjectRequest(WriteWeaviateObject object) { +public record UpdateObjectRequest(WeaviateObject object) { static final Endpoint, Void> endpoint( CollectionDescriptor collection, CollectionHandleDefaults defaults) { - final var typeToken = TypeToken.getParameterized(WriteWeaviateObject.class, collection.typeToken().getType()); + final var typeToken = TypeToken.getParameterized(WeaviateObject.class, collection.typeToken().getType()); return SimpleEndpoint.sideEffect( request -> "PATCH", @@ -29,7 +30,7 @@ static final Endpoint, Void> endp ? Map.of("consistency_level", defaults.consistencyLevel()) : Collections.emptyMap(), request -> JSON.serialize( - new WriteWeaviateObject<>( + new WeaviateObject<>( request.object.uuid(), collection.collectionName(), defaults.tenant(), @@ -37,6 +38,7 @@ static final Endpoint, Void> endp request.object.vectors(), request.object.createdAt(), request.object.lastUpdatedAt(), + null, request.object.references()), typeToken)); } @@ -51,7 +53,7 @@ public UpdateObjectRequest(Builder builder) { } public static class Builder implements ObjectBuilder> { - private final WriteWeaviateObject.Builder object = new WriteWeaviateObject.Builder<>(); + private final WeaviateObject.Builder object = new WeaviateObject.Builder<>(); public Builder(String uuid) { this.object.uuid(uuid); @@ -67,7 +69,7 @@ public Builder vectors(Vectors... vectors) { return this; } - public Builder reference(String property, Reference... references) { + public Builder reference(String property, ObjectReference... references) { this.object.reference(property, references); return this; } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java index 953a920d9..c7497ec64 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java @@ -6,9 +6,10 @@ import java.util.function.Function; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; -import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClient; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.client6.v1.api.collections.query.FilterOperand; +import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClient; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; @@ -43,18 +44,18 @@ public WeaviateDataClient(WeaviateDataClient c, CollectionHandleDef this.defaults = defaults; } - public WriteWeaviateObject insert(PropertiesT properties) throws IOException { + public WeaviateObject insert(PropertiesT properties) throws IOException { return insert(InsertObjectRequest.of(properties)); } - public WriteWeaviateObject insert( + public WeaviateObject insert( PropertiesT properties, - Function, ObjectBuilder>> fn) + Function, ObjectBuilder>> fn) throws IOException { return insert(InsertObjectRequest.of(properties, fn)); } - public WriteWeaviateObject insert(InsertObjectRequest request) + public WeaviateObject insert(InsertObjectRequest request) throws IOException { return this.restTransport.performRequest(request, InsertObjectRequest.endpoint(collection, defaults)); } @@ -64,12 +65,12 @@ public final InsertManyResponse insertMany(PropertiesT... objects) { return insertMany(InsertManyRequest.of(objects)); } - public InsertManyResponse insertMany(List> objects) { + public InsertManyResponse insertMany(List> objects) { return insertMany(new InsertManyRequest<>(objects)); } @SafeVarargs - public final InsertManyResponse insertMany(WriteWeaviateObject... objects) { + public final InsertManyResponse insertMany(WeaviateObject... objects) { return insertMany(Arrays.asList(objects)); } @@ -102,7 +103,8 @@ public void replace( * Delete an object by its UUID. * * @param uuid The UUID of the object to delete. - * @return {@code true} if the object was deleted, {@code false} if there was no object to delete. + * @return {@code true} if the object was deleted, {@code false} if there was no + * object to delete. * @throws IOException in case the request was not sent successfully. */ public boolean deleteById(String uuid) throws IOException { @@ -130,12 +132,9 @@ public DeleteManyResponse deleteMany(DeleteManyRequest request) { return this.grpcTransport.performRequest(request, DeleteManyRequest.rpc(collection, defaults)); } - public void referenceAdd(String fromUuid, String fromProperty, Reference reference) throws IOException { - for (var uuid : reference.uuids()) { - var singleRef = new Reference(reference.collection(), uuid); - this.restTransport.performRequest(new ReferenceAddRequest(fromUuid, fromProperty, singleRef), - ReferenceAddRequest.endpoint(collection, defaults)); - } + public void referenceAdd(String fromUuid, String fromProperty, ObjectReference reference) throws IOException { + this.restTransport.performRequest(new ReferenceAddRequest(fromUuid, fromProperty, reference), + ReferenceAddRequest.endpoint(collection, defaults)); } public ReferenceAddManyResponse referenceAddMany(BatchReference... references) throws IOException { @@ -147,19 +146,13 @@ public ReferenceAddManyResponse referenceAddMany(List references ReferenceAddManyRequest.endpoint(references, defaults)); } - public void referenceDelete(String fromUuid, String fromProperty, Reference reference) throws IOException { - for (var uuid : reference.uuids()) { - var singleRef = new Reference(reference.collection(), uuid); - this.restTransport.performRequest(new ReferenceDeleteRequest(fromUuid, fromProperty, singleRef), - ReferenceDeleteRequest.endpoint(collection, defaults)); - } + public void referenceDelete(String fromUuid, String fromProperty, ObjectReference reference) throws IOException { + this.restTransport.performRequest(new ReferenceDeleteRequest(fromUuid, fromProperty, reference), + ReferenceDeleteRequest.endpoint(collection, defaults)); } - public void referenceReplace(String fromUuid, String fromProperty, Reference reference) throws IOException { - for (var uuid : reference.uuids()) { - var singleRef = new Reference(reference.collection(), uuid); - this.restTransport.performRequest(new ReferenceReplaceRequest(fromUuid, fromProperty, singleRef), - ReferenceReplaceRequest.endpoint(collection, defaults)); - } + public void referenceReplace(String fromUuid, String fromProperty, ObjectReference reference) throws IOException { + this.restTransport.performRequest(new ReferenceReplaceRequest(fromUuid, fromProperty, reference), + ReferenceReplaceRequest.endpoint(collection, defaults)); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java index 7ac560fc9..cdbb2b08b 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java @@ -1,16 +1,16 @@ package io.weaviate.client6.v1.api.collections.data; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Function; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; -import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClientAsync; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.client6.v1.api.collections.query.FilterOperand; +import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClientAsync; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; @@ -45,17 +45,17 @@ public WeaviateDataClientAsync(WeaviateDataClientAsync c, Collectio this.defaults = defaults; } - public CompletableFuture> insert(PropertiesT properties) { + public CompletableFuture> insert(PropertiesT properties) { return insert(InsertObjectRequest.of(properties)); } - public CompletableFuture> insert( + public CompletableFuture> insert( PropertiesT properties, - Function, ObjectBuilder>> fn) { + Function, ObjectBuilder>> fn) { return insert(InsertObjectRequest.of(properties, fn)); } - public CompletableFuture> insert( + public CompletableFuture> insert( InsertObjectRequest request) { return this.restTransport.performRequestAsync(request, InsertObjectRequest.endpoint(collection, defaults)); } @@ -66,11 +66,11 @@ public final CompletableFuture insertMany(PropertiesT... obj } @SafeVarargs - public final CompletableFuture insertMany(WriteWeaviateObject... objects) { + public final CompletableFuture insertMany(WeaviateObject... objects) { return insertMany(Arrays.asList(objects)); } - public CompletableFuture insertMany(List> objects) { + public CompletableFuture insertMany(List> objects) { return insertMany(new InsertManyRequest<>(objects)); } @@ -122,12 +122,9 @@ public CompletableFuture deleteMany(DeleteManyRequest reques return this.grpcTransport.performRequestAsync(request, DeleteManyRequest.rpc(collection, defaults)); } - public CompletableFuture referenceAdd(String fromUuid, String fromProperty, Reference reference) { - return forEachAsync(reference.uuids(), uuid -> { - var singleRef = new Reference(reference.collection(), (String) uuid); - return this.restTransport.performRequestAsync(new ReferenceAddRequest(fromUuid, fromProperty, singleRef), - ReferenceAddRequest.endpoint(collection, defaults)); - }); + public CompletableFuture referenceAdd(String fromUuid, String fromProperty, ObjectReference reference) { + return this.restTransport.performRequestAsync(new ReferenceAddRequest(fromUuid, fromProperty, reference), + ReferenceAddRequest.endpoint(collection, defaults)); } public CompletableFuture referenceAddMany(BatchReference... references) { @@ -139,41 +136,13 @@ public CompletableFuture referenceAddMany(List referenceDelete(String fromUuid, String fromProperty, Reference reference) { - return forEachAsync(reference.uuids(), uuid -> { - var singleRef = new Reference(reference.collection(), (String) uuid); - return this.restTransport.performRequestAsync(new ReferenceDeleteRequest(fromUuid, fromProperty, singleRef), - ReferenceDeleteRequest.endpoint(collection, defaults)); - }); - } - - public CompletableFuture referenceReplace(String fromUuid, String fromProperty, Reference reference) { - return forEachAsync(reference.uuids(), uuid -> { - var singleRef = new Reference(reference.collection(), (String) uuid); - return this.restTransport.performRequestAsync(new ReferenceReplaceRequest(fromUuid, fromProperty, singleRef), - ReferenceReplaceRequest.endpoint(collection, defaults)); - }); - } - - /** - * Spawn execution {@code fn} for each of the {@code elements} and return a - * flattened {@link CompletableFuture#allOf}. - * - *

- * Usage: - * - *

{@code
-   *  // With elements immediately available
-   *  forEachAsync(myElements, element -> doNetworkIo(element));
-   *
-   *  // Chain to another CompletableFuture
-   *  fetch(request).thenCompose(elements -> forEachAsync(...));
-   * }
- */ - private static CompletableFuture forEachAsync(Collection elements, - Function> fn) { - var futures = elements.stream().map(el -> fn.apply(el)) - .toArray(CompletableFuture[]::new); - return CompletableFuture.allOf(futures); + public CompletableFuture referenceDelete(String fromUuid, String fromProperty, ObjectReference reference) { + return this.restTransport.performRequestAsync(new ReferenceDeleteRequest(fromUuid, fromProperty, reference), + ReferenceDeleteRequest.endpoint(collection, defaults)); + } + + public CompletableFuture referenceReplace(String fromUuid, String fromProperty, ObjectReference reference) { + return this.restTransport.performRequestAsync(new ReferenceReplaceRequest(fromUuid, fromProperty, reference), + ReferenceReplaceRequest.endpoint(collection, defaults)); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/WriteWeaviateObject.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/WriteWeaviateObject.java deleted file mode 100644 index 673157532..000000000 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/WriteWeaviateObject.java +++ /dev/null @@ -1,202 +0,0 @@ -package io.weaviate.client6.v1.api.collections.data; - -import java.io.IOException; -import java.lang.reflect.ParameterizedType; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.annotations.SerializedName; -import com.google.gson.internal.Streams; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -import io.weaviate.client6.v1.api.collections.Vectors; -import io.weaviate.client6.v1.api.collections.WeaviateObject; -import io.weaviate.client6.v1.internal.ObjectBuilder; - -public record WriteWeaviateObject( - @SerializedName("id") String uuid, - @SerializedName("class") String collection, - @SerializedName("tenant") String tenant, - @SerializedName("properties") PropertiesT properties, - @SerializedName("vectors") Vectors vectors, - @SerializedName("creationTimeUnix") Long createdAt, - @SerializedName("lastUpdateTimeUnix") Long lastUpdatedAt, - - Map> references) implements WeaviateObject { - - public static WriteWeaviateObject of( - Function, ObjectBuilder>> fn) { - return fn.apply(new Builder<>()).build(); - } - - public WriteWeaviateObject(Builder builder) { - this( - builder.uuid, - builder.collection, - builder.tenant, - builder.properties, - builder.vectors, - null, // creationTimeUnix is read-only - null, // lastUpdateTimeUnix is read-only - builder.references); - } - - public static class Builder implements ObjectBuilder> { - /** - * The server should be providing default UUIDs, but it does not do that - * during batch inserts and we have to provide our own. - * Rather than make this behaviour special to {@code insertMany}, we are going - * to provide a fallback UUID "globally". - */ - private String uuid = UUID.randomUUID().toString(); - private String collection; - private String tenant; - private PropertiesT properties; - private Vectors vectors; - private Map> references = new HashMap<>(); - - public Builder uuid(String uuid) { - this.uuid = uuid; - return this; - } - - public Builder tenant(String tenant) { - this.tenant = tenant; - return this; - } - - public Builder properties(PropertiesT properties) { - this.properties = properties; - return this; - } - - /** - * Add a reference. Calls to {@link #reference} can be chained - * to add multiple references. - */ - public Builder reference(String property, Reference... references) { - for (var ref : references) { - addReference(property, ref); - } - return this; - } - - public Builder references(Map> references) { - this.references = references; - return this; - } - - private void addReference(String property, Reference reference) { - if (!references.containsKey(property)) { - references.put(property, new ArrayList<>()); - } - references.get(property).add(reference); - } - - public Builder vectors(Vectors... vectors) { - if (this.vectors == null) { - this.vectors = vectors.length == 1 ? vectors[0] : new Vectors(vectors); - } else { - this.vectors = this.vectors.withVectors(vectors); - } - return this; - } - - @Override - public WriteWeaviateObject build() { - return new WriteWeaviateObject<>(this); - } - } - - public static enum CustomTypeAdapterFactory implements TypeAdapterFactory { - INSTANCE; - - @SuppressWarnings("unchecked") - @Override - public TypeAdapter create(Gson gson, TypeToken typeToken) { - var type = typeToken.getType(); - var rawType = typeToken.getRawType(); - if (rawType != WriteWeaviateObject.class || - !(type instanceof ParameterizedType parameterized) - || parameterized.getActualTypeArguments().length != 1) { - return null; - } - - var typeParams = parameterized.getActualTypeArguments(); - final var propertiesType = typeParams[0]; - - final var delegate = (TypeAdapter>) gson - .getDelegateAdapter(this, typeToken); - final var propertiesAdapter = (TypeAdapter) gson.getAdapter(TypeToken.get(propertiesType)); - final var referencesAdapter = gson.getAdapter(Reference.class); - - return (TypeAdapter) new TypeAdapter>() { - - @Override - public void write(JsonWriter out, WriteWeaviateObject value) throws IOException { - var json = delegate.toJsonTree(value).getAsJsonObject(); - var properties = value.properties() != null - ? propertiesAdapter.toJsonTree(value.properties()).getAsJsonObject() - : new JsonObject(); - - if (value.references() != null && !value.references().isEmpty()) { - for (var refEntry : value.references().entrySet()) { - var beacons = new JsonArray(); - for (var reference : refEntry.getValue()) { - var beacon = referencesAdapter.toJsonTree(reference); - beacons.add(beacon); - } - properties.add(refEntry.getKey(), beacons); - } - } - - json.add("properties", properties); - json.remove("references"); - Streams.write(json, out); - } - - @Override - public WriteWeaviateObject read(JsonReader in) throws IOException { - var json = JsonParser.parseReader(in).getAsJsonObject(); - - var jsonProperties = json.get("properties").getAsJsonObject(); - var objectProperties = new JsonObject(); - var objectReferences = new JsonObject(); - - for (var property : jsonProperties.entrySet()) { - var value = property.getValue(); - - if (value.isJsonArray()) { - var array = value.getAsJsonArray(); - var first = array.get(0); - var isReference = first.isJsonObject() && first.getAsJsonObject().has("beacon"); - - if (isReference) { - objectReferences.add(property.getKey(), value); - continue; - } - } - - objectProperties.add(property.getKey(), value); - } - - json.add("references", objectReferences); - json.add("properties", objectProperties); - return delegate.fromJsonTree(json); - } - }.nullSafe(); - } - } -} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeObject.java b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeObject.java index 79f735b3c..b0e95dcc1 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeObject.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeObject.java @@ -4,20 +4,14 @@ import io.weaviate.client6.v1.api.collections.query.QueryMetadata; public record GenerativeObject( - /** Object properties. */ - PropertiesT properties, - /** Object metadata. */ - QueryMetadata metadata, - /** Generative task output. */ - TaskOutput generative) { - - /** Shorthand for accessing objects's UUID from metadata. */ - public String uuid() { - return metadata.uuid(); - } - - /** Shorthand for accessing objects's vectors from metadata. */ - public Vectors vectors() { - return metadata.vectors(); - } + /** Object UUID. */ + String uuid, + /** Retrieved object vectors. */ + Vectors vectors, + /** Object properties. */ + PropertiesT properties, + /** Object metadata. */ + QueryMetadata metadata, + /** Generative task output. */ + TaskOutput generative) { } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponse.java b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponse.java index 275722e52..e4db43a9d 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponse.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponse.java @@ -40,8 +40,10 @@ static GenerativeResponse unmarshal( generative = GenerativeResponse.unmarshalTaskOutput(result.getGenerative()); } return new GenerativeObject<>( + object.uuid(), + object.vectors(), object.properties(), - object.metadata(), + object.queryMetadata(), generative); }) .toList(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponseGrouped.java b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponseGrouped.java index 9c8504894..95710580c 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponseGrouped.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/generate/GenerativeResponseGrouped.java @@ -36,8 +36,10 @@ static GenerativeResponseGrouped unmarshal( object.getMetadata(), collection)) .map(object -> new QueryObjectGrouped<>( + object.uuid(), + object.vectors(), object.properties(), - object.metadata(), + object.queryMetadata(), groupName)) .toList(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPage.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPage.java index 0e7046fbe..6a4f1bdc0 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPage.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPage.java @@ -7,31 +7,31 @@ import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; +import io.weaviate.client6.v1.api.collections.WeaviateObject; -public final class AsyncPage implements Iterable> { +public final class AsyncPage implements Iterable> { private final int pageSize; - private final BiFunction>>> fetch; + private final BiFunction>>> fetch; private final String cursor; - private List> currentPage = new ArrayList<>(); + private List> currentPage = new ArrayList<>(); AsyncPage(String cursor, int pageSize, - BiFunction>>> fetch) { + BiFunction>>> fetch) { this.cursor = cursor; this.pageSize = pageSize; this.fetch = fetch; } AsyncPage(String cursor, int pageSize, - BiFunction>>> fetch, - List> currentPage) { + BiFunction>>> fetch, + List> currentPage) { this(cursor, pageSize, fetch); this.currentPage = Collections.unmodifiableList(currentPage); } - List> items() { + List> items() { return currentPage; } @@ -68,7 +68,7 @@ public CompletableFuture> fetchNextPage() { } @Override - public Iterator> iterator() { + public Iterator> iterator() { return currentPage.iterator(); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java index c82c2df3e..caa321837 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java @@ -5,11 +5,11 @@ import java.util.function.Consumer; import java.util.function.Function; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.query.FetchObjects; import io.weaviate.client6.v1.api.collections.query.Metadata; import io.weaviate.client6.v1.api.collections.query.QueryReference; import io.weaviate.client6.v1.api.collections.query.QueryResponse; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClientAsync; import io.weaviate.client6.v1.internal.ObjectBuilder; @@ -45,25 +45,25 @@ public AsyncPaginator(Builder builder) { this.resultSet = builder.prefetch ? rs.fetchNextPage() : CompletableFuture.completedFuture(rs); } - public CompletableFuture forEach(Consumer> action) { + public CompletableFuture forEach(Consumer> action) { return resultSet .thenCompose(rs -> rs.isEmpty() ? rs.fetchNextPage() : CompletableFuture.completedFuture(rs)) .thenCompose(processEachAndAdvance(action)); } - public CompletableFuture forPage(Consumer>> action) { + public CompletableFuture forPage(Consumer>> action) { return resultSet .thenCompose(rs -> rs.isEmpty() ? rs.fetchNextPage() : CompletableFuture.completedFuture(rs)) .thenCompose(processPageAndAdvance(action)); } private static Function, CompletableFuture> processEachAndAdvance( - Consumer> action) { + Consumer> action) { return processAndAdvanceFunc(rs -> rs.forEach(action)); } private static Function, CompletableFuture> processPageAndAdvance( - Consumer>> action) { + Consumer>> action) { return processAndAdvanceFunc(rs -> action.accept(rs.items())); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/CursorSpliterator.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/CursorSpliterator.java index eb45e0402..815b01714 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/CursorSpliterator.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/CursorSpliterator.java @@ -7,26 +7,26 @@ import java.util.function.BiFunction; import java.util.function.Consumer; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; +import io.weaviate.client6.v1.api.collections.WeaviateObject; -public class CursorSpliterator implements Spliterator> { +public class CursorSpliterator implements Spliterator> { private final int pageSize; - private final BiFunction>> fetch; + private final BiFunction>> fetch; // Spliterators do not promise thread-safety, so there's no mechanism // to protect access to its internal state. private String cursor; - private Iterator> currentPage = Collections.emptyIterator(); + private Iterator> currentPage = Collections.emptyIterator(); public CursorSpliterator(String cursor, int pageSize, - BiFunction>> fetch) { + BiFunction>> fetch) { this.cursor = cursor; this.pageSize = pageSize; this.fetch = fetch; } @Override - public boolean tryAdvance(Consumer> action) { + public boolean tryAdvance(Consumer> action) { // Happy path: there are remaining objects in the current page. if (currentPage.hasNext()) { action.accept(currentPage.next()); @@ -53,7 +53,7 @@ public boolean tryAdvance(Consumer> acti } @Override - public Spliterator> trySplit() { + public Spliterator> trySplit() { // Do not support splitting just now; return null; } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java index f6893f58b..8ad18fd67 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java @@ -8,15 +8,15 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.query.FetchObjects; import io.weaviate.client6.v1.api.collections.query.Filter; import io.weaviate.client6.v1.api.collections.query.Metadata; import io.weaviate.client6.v1.api.collections.query.QueryReference; -import io.weaviate.client6.v1.api.collections.query.ReadWeaviateObject; import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClient; import io.weaviate.client6.v1.internal.ObjectBuilder; -public class Paginator implements Iterable> { +public class Paginator implements Iterable> { static final int DEFAULT_PAGE_SIZE = 100; private final WeaviateQueryClient query; @@ -25,15 +25,15 @@ public class Paginator implements Iterable> iterator() { + public Iterator> iterator() { return Spliterators.iterator(spliterator()); } - public Stream> stream() { + public Stream> stream() { return StreamSupport.stream(spliterator(), false); } - public Spliterator> spliterator() { + public Spliterator> spliterator() { return new CursorSpliterator(cursor, pageSize, (after, limit) -> { var fn = ObjectBuilder.partial(queryOptions, q -> q.after(after).limit(limit)); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/AbstractQueryClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/AbstractQueryClient.java index b90c6d748..468643ece 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/AbstractQueryClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/AbstractQueryClient.java @@ -7,6 +7,7 @@ import io.weaviate.client6.v1.api.WeaviateApiException; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; @@ -72,7 +73,7 @@ public SingleT fetchObjectById(String uuid, Function Optional> optionalFirst(QueryResponse

response) { + protected final

Optional> optionalFirst(QueryResponse

response) { return response == null || response.objects().isEmpty() ? Optional.empty() : Optional.ofNullable(response.objects().get(0)); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryMetadata.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryMetadata.java index 03896895d..dd8a54bfb 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryMetadata.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryMetadata.java @@ -1,33 +1,18 @@ package io.weaviate.client6.v1.api.collections.query; -import io.weaviate.client6.v1.api.collections.Vectors; -import io.weaviate.client6.v1.api.collections.WeaviateMetadata; import io.weaviate.client6.v1.internal.ObjectBuilder; public record QueryMetadata( - /** Object UUID. */ - String uuid, - /** Vector embeddings associated with the object. */ - Vectors vectors, - /** Object creation time as a Unix timestamp. */ - Long creationTimeUnix, - /** Unix timestamp of the latest object update. */ - Long lastUpdateTimeUnix, - /** Distances to the search vector. */ Float distance, /** Distance metric normalized to {@code 0 <= c <= 1} range. */ Float certainty, /** BM25 ranking score. */ Float score, /** Components of the BM25 ranking score. */ - String explainScore) implements WeaviateMetadata { + String explainScore) { private QueryMetadata(Builder builder) { this( - builder.uuid, - builder.vectors, - builder.creationTimeUnix, - builder.lastUpdateTimeUnix, builder.distance, builder.certainty, builder.score, @@ -35,39 +20,11 @@ private QueryMetadata(Builder builder) { } static class Builder implements ObjectBuilder { - private String uuid; - private Vectors vectors; - private Long creationTimeUnix; - private Long lastUpdateTimeUnix; private Float distance; private Float certainty; private Float score; private String explainScore; - final Builder uuid(String uuid) { - this.uuid = uuid; - return this; - } - - public Builder vectors(Vectors... vectors) { - if (this.vectors == null) { - this.vectors = vectors.length == 1 ? vectors[0] : new Vectors(vectors); - } else { - this.vectors = this.vectors.withVectors(vectors); - } - return this; - } - - final Builder creationTimeUnix(Long creationTimeUnix) { - this.creationTimeUnix = creationTimeUnix; - return this; - } - - final Builder lastUpdateTimeUnix(Long lastUpdateTimeUnix) { - this.lastUpdateTimeUnix = lastUpdateTimeUnix; - return this; - } - final Builder distance(Float distance) { this.distance = distance; return this; diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryObjectGrouped.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryObjectGrouped.java index fb6b711d8..9f8ca1133 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryObjectGrouped.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryObjectGrouped.java @@ -1,6 +1,11 @@ package io.weaviate.client6.v1.api.collections.query; +import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; + public record QueryObjectGrouped( + String uuid, + Vectors vectors, /** Object properties. */ PropertiesT properties, /** Object metadata. */ @@ -8,8 +13,13 @@ public record QueryObjectGrouped( /** Name of the group that the object belongs to. */ String belongsToGroup) { - QueryObjectGrouped(ReadWeaviateObject object, + QueryObjectGrouped(WeaviateObject object, String belongsToGroup) { - this(object.properties(), object.metadata(), belongsToGroup); + this( + object.uuid(), + object.vectors(), + object.properties(), + object.queryMetadata(), + belongsToGroup); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryResponse.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryResponse.java index af31ceb12..b1bc7369e 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryResponse.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryResponse.java @@ -3,12 +3,15 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.stream.Stream; import io.weaviate.client6.v1.api.collections.GeoCoordinates; import io.weaviate.client6.v1.api.collections.PhoneNumber; +import io.weaviate.client6.v1.api.collections.Reference; import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.DateUtil; import io.weaviate.client6.v1.internal.grpc.ByteStringUtil; import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateProtoProperties; @@ -17,7 +20,7 @@ import io.weaviate.client6.v1.internal.orm.PropertiesBuilder; public record QueryResponse( - List> objects) { + List> objects) { static QueryResponse unmarshal(WeaviateProtoSearchGet.SearchReply reply, CollectionDescriptor collection) { @@ -30,20 +33,21 @@ static QueryResponse unmarshal(WeaviateProtoSearchGet return new QueryResponse<>(objects); } - public static ReadWeaviateObject unmarshalResultObject( + public static WeaviateObject unmarshalResultObject( WeaviateProtoSearchGet.PropertiesResult propertiesResult, WeaviateProtoSearchGet.MetadataResult metadataResult, CollectionDescriptor collection) { var object = unmarshalWithReferences(propertiesResult, metadataResult, collection); - var metadata = new QueryMetadata.Builder() - .uuid(object.metadata().uuid()) - .vectors(object.metadata().vectors()); + + Long createdAt = null; + Long lastUpdatedAt = null; + var metadata = new QueryMetadata.Builder(); if (metadataResult.getCreationTimeUnixPresent()) { - metadata.creationTimeUnix(metadataResult.getCreationTimeUnix()); + createdAt = metadataResult.getCreationTimeUnix(); } if (metadataResult.getLastUpdateTimeUnixPresent()) { - metadata.lastUpdateTimeUnix(metadataResult.getLastUpdateTimeUnix()); + lastUpdatedAt = metadataResult.getLastUpdateTimeUnix(); } if (metadataResult.getDistancePresent()) { metadata.distance(metadataResult.getDistance()); @@ -57,11 +61,19 @@ public static ReadWeaviateObject unmarshalResultObjec if (metadataResult.getExplainScorePresent()) { metadata.explainScore(metadataResult.getExplainScore()); } - return new ReadWeaviateObject<>(collection.collectionName(), object.properties(), object.references(), - metadata.build()); + return new WeaviateObject<>( + object.uuid(), + collection.collectionName(), + null, // tenant is not reeturned in the query + object.properties(), + object.vectors(), + createdAt, + lastUpdatedAt, + metadata.build(), + object.references()); } - static ReadWeaviateObject unmarshalWithReferences( + static WeaviateObject unmarshalWithReferences( WeaviateProtoSearchGet.PropertiesResult propertiesResult, WeaviateProtoSearchGet.MetadataResult metadataResult, CollectionDescriptor descriptor) { @@ -76,18 +88,24 @@ static ReadWeaviateObject unmarshalWithReferences( // I.e. { "ref": A-1 } , { "ref": B-1 } => { "ref": [A-1, B-1] } var referenceProperties = propertiesResult.getRefPropsList() .stream().reduce( - new HashMap>>(), + new HashMap>(), (map, ref) -> { var refObjects = ref.getPropertiesList().stream() .map(property -> { var reference = unmarshalWithReferences( property, property.getMetadata(), CollectionDescriptor.ofMap(property.getTargetCollection())); - return new ReadWeaviateObject<>( + return (Reference) new WeaviateObject<>( + reference.uuid(), reference.collection(), - (Object) reference.properties(), - reference.references(), - reference.metadata()); + // TODO(dyma): we can get tenant from CollectionHandle + null, // tenant is not returned in the query + (Map) reference.properties(), + reference.vectors(), + reference.createdAt(), + reference.lastUpdatedAt(), + reference.queryMetadata(), + reference.references()); }) .toList(); @@ -108,42 +126,51 @@ static ReadWeaviateObject unmarshalWithReferences( return left; }); + String uuid = null; + Vectors vectors = null; QueryMetadata metadata = null; if (metadataResult != null) { - var metadataBuilder = new QueryMetadata.Builder() - .uuid(metadataResult.getId()); - - var vectors = new Vectors[metadataResult.getVectorsList().size()]; - var i = 0; - for (final var vector : metadataResult.getVectorsList()) { - var vectorName = vector.getName(); - var vbytes = vector.getVectorBytes(); - switch (vector.getType()) { - case VECTOR_TYPE_SINGLE_FP32: - vectors[i++] = Vectors.of(vectorName, ByteStringUtil.decodeVectorSingle(vbytes)); - break; - case VECTOR_TYPE_MULTI_FP32: - vectors[i++] = Vectors.of(vectorName, ByteStringUtil.decodeVectorMulti(vbytes)); - break; - default: - continue; - } - } - metadataBuilder.vectors(vectors); + var metadataBuilder = new QueryMetadata.Builder(); + uuid = metadataResult.getId(); + + // Read legacy (unnamed) vector. if (metadataResult.getVectorBytes() != null && !metadataResult.getVectorBytes().isEmpty()) { var unnamed = ByteStringUtil.decodeVectorSingle(metadataResult.getVectorBytes()); - metadataBuilder.vectors(Vectors.of(unnamed)); + vectors = Vectors.of(unnamed); + } else { + var namedVectors = new Vectors[metadataResult.getVectorsList().size()]; + var i = 0; + for (final var vector : metadataResult.getVectorsList()) { + var vectorName = vector.getName(); + var vbytes = vector.getVectorBytes(); + switch (vector.getType()) { + case VECTOR_TYPE_SINGLE_FP32: + namedVectors[i++] = Vectors.of(vectorName, ByteStringUtil.decodeVectorSingle(vbytes)); + break; + case VECTOR_TYPE_MULTI_FP32: + namedVectors[i++] = Vectors.of(vectorName, ByteStringUtil.decodeVectorMulti(vbytes)); + break; + default: + continue; + } + } + vectors = new Vectors(namedVectors); } metadata = metadataBuilder.build(); } - return new ReadWeaviateObject<>( + return new WeaviateObject<>( + uuid, descriptor.collectionName(), + null, // tenant is not returned in the query properties.build(), - referenceProperties, - metadata); + vectors, + null, + null, + metadata, + referenceProperties); } static void setProperty(String property, WeaviateProtoProperties.Value value, diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/ReadWeaviateObject.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/ReadWeaviateObject.java deleted file mode 100644 index 7f8505b79..000000000 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/ReadWeaviateObject.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.weaviate.client6.v1.api.collections.query; - -import java.util.List; -import java.util.Map; - -import io.weaviate.client6.v1.api.collections.Vectors; -import io.weaviate.client6.v1.api.collections.WeaviateObject; - -public record ReadWeaviateObject( - String collection, - PropertiesT properties, - Map>> references, - QueryMetadata metadata) implements WeaviateObject { - - /** Shorthand for accesing objects's UUID from metadata. */ - @Override - public String uuid() { - return metadata.uuid(); - } - - /** Shorthand for accesing objects's vectors from metadata. */ - @Override - public Vectors vectors() { - return metadata.vectors(); - } -} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClient.java index 24c53b753..25e899b56 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClient.java @@ -3,12 +3,13 @@ import java.util.Optional; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; public class WeaviateQueryClient extends - AbstractQueryClient>, QueryResponse, QueryResponseGrouped> { + AbstractQueryClient>, QueryResponse, QueryResponseGrouped> { public WeaviateQueryClient( CollectionDescriptor collection, @@ -23,7 +24,7 @@ public WeaviateQueryClient(WeaviateQueryClient c, CollectionHandleD } @Override - protected Optional> fetchObjectById(FetchObjectById byId) { + protected Optional> fetchObjectById(FetchObjectById byId) { var request = new QueryRequest(byId, null); var result = this.grpcTransport.performRequest(request, QueryRequest.rpc(collection, defaults)); return optionalFirst(result); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClientAsync.java index 13bf9ce6d..41a7d902b 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/WeaviateQueryClientAsync.java @@ -4,12 +4,13 @@ import java.util.concurrent.CompletableFuture; import io.weaviate.client6.v1.api.collections.CollectionHandleDefaults; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.internal.grpc.GrpcTransport; import io.weaviate.client6.v1.internal.orm.CollectionDescriptor; public class WeaviateQueryClientAsync extends - AbstractQueryClient>>, CompletableFuture>, CompletableFuture>> { + AbstractQueryClient>>, CompletableFuture>, CompletableFuture>> { public WeaviateQueryClientAsync( CollectionDescriptor collection, @@ -24,7 +25,7 @@ public WeaviateQueryClientAsync(WeaviateQueryClientAsync qc, Collec } @Override - protected CompletableFuture>> fetchObjectById( + protected CompletableFuture>> fetchObjectById( FetchObjectById byId) { var request = new QueryRequest(byId, null); var result = this.grpcTransport.performRequestAsync(request, QueryRequest.rpc(collection, defaults)); diff --git a/src/main/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtil.java b/src/main/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtil.java index 6bee6de0a..335c428d7 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtil.java +++ b/src/main/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtil.java @@ -16,11 +16,14 @@ private ByteStringUtil() { private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; /** Decode ByteString to UUID. */ - public static UUID decodeUuid(ByteString bs) { + public static String decodeUuid(ByteString bs) { + if (bs.size() != Long.BYTES * 2) { + return null; + } var buf = ByteBuffer.wrap(bs.toByteArray()); var most = buf.getLong(); var least = buf.getLong(); - return new UUID(most, least); + return new UUID(most, least).toString(); } /** Encode float[] to ByteString. */ diff --git a/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java b/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java index d69e7fdaa..85bf428bc 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java +++ b/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java @@ -23,7 +23,7 @@ public final class JSON { gsonBuilder.registerTypeAdapterFactory( io.weaviate.client6.v1.api.rbac.Role.CustomTypeAdapterFactory.INSTANCE); gsonBuilder.registerTypeAdapterFactory( - io.weaviate.client6.v1.api.collections.data.WriteWeaviateObject.CustomTypeAdapterFactory.INSTANCE); + io.weaviate.client6.v1.api.collections.WeaviateObject.CustomTypeAdapterFactory.INSTANCE); gsonBuilder.registerTypeAdapterFactory( io.weaviate.client6.v1.api.collections.CollectionConfig.CustomTypeAdapterFactory.INSTANCE); gsonBuilder.registerTypeAdapterFactory( @@ -56,8 +56,11 @@ public final class JSON { // TypeAdapters ----------------------------------------------------------- gsonBuilder.registerTypeAdapter( - io.weaviate.client6.v1.api.collections.data.Reference.class, - io.weaviate.client6.v1.api.collections.data.Reference.TYPE_ADAPTER); + io.weaviate.client6.v1.api.collections.data.ObjectReference.class, + io.weaviate.client6.v1.api.collections.data.ObjectReference.TYPE_ADAPTER); + gsonBuilder.registerTypeAdapter( + io.weaviate.client6.v1.api.collections.Reference.class, + io.weaviate.client6.v1.api.collections.data.ObjectReference.TYPE_ADAPTER); gsonBuilder.registerTypeAdapter( io.weaviate.client6.v1.api.collections.data.BatchReference.class, io.weaviate.client6.v1.api.collections.data.BatchReference.TYPE_ADAPTER); diff --git a/src/test/java/io/weaviate/client6/v1/api/collections/CollectionHandleTest.java b/src/test/java/io/weaviate/client6/v1/api/collections/CollectionHandleTest.java index e775e92cf..9cf1e99d9 100644 --- a/src/test/java/io/weaviate/client6/v1/api/collections/CollectionHandleTest.java +++ b/src/test/java/io/weaviate/client6/v1/api/collections/CollectionHandleTest.java @@ -14,7 +14,7 @@ import com.jparams.junit4.data.DataMethod; import com.jparams.junit4.description.Name; -import io.weaviate.client6.v1.api.collections.data.Reference; +import io.weaviate.client6.v1.api.collections.data.ObjectReference; import io.weaviate.client6.v1.api.collections.query.ConsistencyLevel; import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.grpc.protocol.WeaviateProtoBase; @@ -86,7 +86,7 @@ public static Object[][] restTestCases() { "data::add reference", ConsistencyLevel.ONE, Location.QUERY, "john_doe", Location.QUERY, - (Act) c -> c.data.referenceAdd("from-uuid", "from_property", Reference.uuids("to-uuid")), + (Act) c -> c.data.referenceAdd("from-uuid", "from_property", ObjectReference.uuid("to-uuid")), }, { "data::add reference many", @@ -98,13 +98,13 @@ public static Object[][] restTestCases() { "data::replace reference", ConsistencyLevel.ONE, Location.QUERY, "john_doe", Location.QUERY, - (Act) c -> c.data.referenceReplace("from-uuid", "from_property", Reference.uuids("to-uuid")), + (Act) c -> c.data.referenceReplace("from-uuid", "from_property", ObjectReference.uuid("to-uuid")), }, { "data::delete reference", ConsistencyLevel.ONE, Location.QUERY, "john_doe", Location.QUERY, - (Act) c -> c.data.referenceDelete("from-uuid", "from_property", Reference.uuids("to-uuid")), + (Act) c -> c.data.referenceDelete("from-uuid", "from_property", ObjectReference.uuid("to-uuid")), }, }; } diff --git a/src/test/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtilTest.java b/src/test/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtilTest.java index 147549b2c..6d7b3abe8 100644 --- a/src/test/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtilTest.java +++ b/src/test/java/io/weaviate/client6/v1/internal/grpc/ByteStringUtilTest.java @@ -49,10 +49,17 @@ public void test_decodeVector_2d() { public void test_decodeUuid() { byte[] bytes = { 38, 19, -74, 24, -114, -19, 73, 43, -112, -60, 47, 96, 83, -89, -35, -23 }; String want = "2613b618-8eed-492b-90c4-2f6053a7dde9"; - String got = ByteStringUtil.decodeUuid(ByteString.copyFrom(bytes)).toString(); + String got = ByteStringUtil.decodeUuid(ByteString.copyFrom(bytes)); Assertions.assertThat(got).isEqualTo(want); } + @Test + public void test_decodeUuid_bufferUnderflow() { + byte[] bytes = { 38, 19 }; // A valid UUID is exactly 16 bytes + String got = ByteStringUtil.decodeUuid(ByteString.copyFrom(bytes)); + Assertions.assertThat(got).isNull(); + } + @Test public void test_decodeVector_1d_empty() { byte[] bytes = new byte[0]; diff --git a/src/test/java/io/weaviate/client6/v1/internal/json/JSONTest.java b/src/test/java/io/weaviate/client6/v1/internal/json/JSONTest.java index 1439e9a00..958e1e1d7 100644 --- a/src/test/java/io/weaviate/client6/v1/internal/json/JSONTest.java +++ b/src/test/java/io/weaviate/client6/v1/internal/json/JSONTest.java @@ -25,10 +25,10 @@ import io.weaviate.client6.v1.api.collections.Tokenization; import io.weaviate.client6.v1.api.collections.VectorConfig; import io.weaviate.client6.v1.api.collections.Vectors; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.data.BatchReference; -import io.weaviate.client6.v1.api.collections.data.Reference; +import io.weaviate.client6.v1.api.collections.data.ObjectReference; import io.weaviate.client6.v1.api.collections.data.ReferenceAddManyResponse; -import io.weaviate.client6.v1.api.collections.data.WriteWeaviateObject; import io.weaviate.client6.v1.api.collections.quantizers.PQ; import io.weaviate.client6.v1.api.collections.rerankers.CohereReranker; import io.weaviate.client6.v1.api.collections.vectorindex.Distance; @@ -403,21 +403,21 @@ public static Object[][] testCases() { // Reference.TYPE_ADAPTER { - Reference.class, - Reference.uuids("id-1"), + ObjectReference.class, + ObjectReference.uuid("id-1"), "{\"beacon\": \"weaviate://localhost/id-1\"}", }, { - Reference.class, - Reference.collection("Doodlebops", "id-1"), + ObjectReference.class, + ObjectReference.collection("Doodlebops", "id-1"), "{\"beacon\": \"weaviate://localhost/Doodlebops/id-1\"}", }, // WriteWeaviateObject.CustomTypeAdapterFactory.INSTANCE { - new TypeToken>>() { + new TypeToken>>() { }, - new WriteWeaviateObject<>( + new WeaviateObject<>( "thing-1", "Things", /* tenant */ null, @@ -425,7 +425,8 @@ public static Object[][] testCases() { /* vectors */ null, /* creationTimeUnix */ null, /* lastUpdateTimeUnix */ null, - Map.of("hasRef", List.of(Reference.uuids("ref-1")))), + /* queryMetadata */ null, + Map.of("hasRef", List.of(ObjectReference.uuid("ref-1")))), """ { @@ -457,7 +458,7 @@ public static Object[][] testCases() { { BatchReference.class, new BatchReference("FromCollection", "fromProperty", "from-uuid", - Reference.collection("ToCollection", "to-uuid")), + ObjectReference.collection("ToCollection", "to-uuid")), """ { "from": "weaviate://localhost/FromCollection/from-uuid/fromProperty",