From 42c77e8e2bfa50f7004ee33a6ab2710656336edf Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 29 Jul 2025 09:04:07 +0200 Subject: [PATCH 01/18] Add C# docs --- _includes/code/csharp/CollectionTests.cs | 109 ++++++++++++++++++ _includes/code/csharp/ConnectionTests.cs | 27 +++++ _includes/code/csharp/ObjectTests.cs | 53 +++++++++ _includes/code/csharp/SearchTests.cs | 24 ++++ .../code/csharp/WeaviateProject.Tests.csproj | 15 +++ _includes/schema-delete-class.mdx | 9 ++ docs.sln | 32 +++++ docs/weaviate/connections/connect-local.mdx | 9 ++ .../collection-operations.mdx | 17 +++ .../manage-collections/vector-config.mdx | 9 ++ docs/weaviate/manage-objects/create.mdx | 9 ++ docs/weaviate/manage-objects/delete.mdx | 9 ++ docusaurus.config.js | 2 +- 13 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 _includes/code/csharp/CollectionTests.cs create mode 100644 _includes/code/csharp/ConnectionTests.cs create mode 100644 _includes/code/csharp/ObjectTests.cs create mode 100644 _includes/code/csharp/SearchTests.cs create mode 100644 _includes/code/csharp/WeaviateProject.Tests.csproj create mode 100644 docs.sln diff --git a/_includes/code/csharp/CollectionTests.cs b/_includes/code/csharp/CollectionTests.cs new file mode 100644 index 000000000..0934dbd15 --- /dev/null +++ b/_includes/code/csharp/CollectionTests.cs @@ -0,0 +1,109 @@ +using Xunit; +using Weaviate.Client; +using System; +using System.Threading.Tasks; +using Weaviate.Client.Models; + +namespace WeaviateProject.Tests; + +public class CollectionTest +{ + [Fact] + public async Task Should_Create_Collection() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // START BasicCreateCollection + var collectionName = "Article"; + // END BasicCreateCollection + // Clean up previous runs by deleting the collection if it exists + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + Console.WriteLine($"Deleted existing collection: '{collectionName}'"); + } + + // START BasicCreateCollection + var articleCollection = new Collection + { + Name = collectionName, + Description = "Collection description", + }; + + var collection = await client.Collections.Create(articleCollection); + // END BasicCreateCollection + Console.WriteLine($"Successfully created collection: '{collectionName}'"); + } + + [Fact] + public async Task Should_Create_Collection_With_Properties() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // START CreateCollectionWithProperties + var collectionName = "Article"; + // END CreateCollectionWithProperties + // Clean up previous runs by deleting the collection if it exists + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + Console.WriteLine($"Deleted existing collection: '{collectionName}'"); + } + + // START CreateCollectionWithProperties + var articleCollection = new Collection + { + Name = collectionName, + Description = "something", + Properties = [Property.Int("number_property"),Property.Text("test_property")], + }; + + var collection = await client.Collections.Create(articleCollection); + // END CreateCollectionWithProperties + Console.WriteLine($"Successfully created collection: '{collectionName}'"); + } + + [Fact] + public async Task Should_Create_Collection_With_Vectorizer() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // START CreateCollectionWithVectorizer + var collectionName = "Article"; + // END CreateCollectionWithVectorizer + // Clean up previous runs by deleting the collection if it exists + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + Console.WriteLine($"Deleted existing collection: '{collectionName}'"); + } + + // START CreateCollectionWithVectorizer + var articleCollection = new Collection + { + Name = collectionName, + Description = "something", + Properties = [Property.Int("number_property"),Property.Text("test_property")], + VectorConfig = new VectorConfig("vector_name", new Vectorizer.Text2VecContextionary()) + }; + + var collection = await client.Collections.Create(articleCollection); + // END CreateCollectionWithVectorizer + Console.WriteLine($"Successfully created collection: '{collectionName}'"); + } + + [Fact] + public async Task Should_Delete_Collection() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var collectionName = "Article"; + + // Ensure the collection exists before attempting to delete it + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + Console.WriteLine($"Successfully deleted collection: '{collectionName}'"); + } + else + { + Console.WriteLine($"Collection '{collectionName}' does not exist."); + } + } +} diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs new file mode 100644 index 000000000..ed158de63 --- /dev/null +++ b/_includes/code/csharp/ConnectionTests.cs @@ -0,0 +1,27 @@ +using Xunit; +using Weaviate.Client; +using System; +using System.Threading.Tasks; + +namespace WeaviateProject.Tests; + +public class ConnectionTest +{ + [Fact] + public async Task Should_Connect_To_Weaviate() + { + // START LocalNoAuth + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // END LocalNoAuth + // try + // { + // var meta = await client.GetMeta(); + // Assert.NotNull(meta); + // Assert.NotNull(client); + // } + // catch (Exception ex) + // { + // Assert.True(false, $"Connection failed: {ex.Message}"); + // } + } +} diff --git a/_includes/code/csharp/ObjectTests.cs b/_includes/code/csharp/ObjectTests.cs new file mode 100644 index 000000000..e38e6a049 --- /dev/null +++ b/_includes/code/csharp/ObjectTests.cs @@ -0,0 +1,53 @@ +using Xunit; +using Weaviate.Client; +using System; +using System.Threading.Tasks; +using Weaviate.Client.Models; + +namespace WeaviateProject.Tests; + +public class ObjectTest +{ + readonly Guid objectId = Guid.NewGuid(); + readonly string collectionName = "Jeopardy"; + + [Fact] + public async Task Should_Import_Objects() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // START CreateObject + var collectionClient = client.Collections.Use(collectionName); + + var obj = await collectionClient.Data.Insert( + new + { + question = "This vector DB is OSS & supports automatic property type inference on import", + // "answer": "Weaviate", # properties can be omitted + newProperty = 123 + }, + id: objectId + ); + // END CreateObject + Console.WriteLine($"Successfully created collection: '{collectionName}'"); + } + + [Fact] + public async Task Should_Delete_Objects() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var collectionName = "Article"; + + if (await client.Collections.Exists(collectionName)) + { + // START DeleteObject + var collection = client.Collections.Use(collectionName); + await collection.Data.Delete(objectId); + // END DeleteObject + Console.WriteLine($"Successfully deleted object: '{objectId}' from collection: '{collectionName}'"); + } + else + { + Console.WriteLine($"Collection '{collectionName}' does not exist."); + } + } +} diff --git a/_includes/code/csharp/SearchTests.cs b/_includes/code/csharp/SearchTests.cs new file mode 100644 index 000000000..21f6be53c --- /dev/null +++ b/_includes/code/csharp/SearchTests.cs @@ -0,0 +1,24 @@ +using Xunit; +using Weaviate.Client; +using System; +using System.Threading.Tasks; +using Weaviate.Client.Models; + +namespace WeaviateProject.Tests; + +public class SearchTest +{ + [Fact] + public async Task Should_Fetch_By_Id() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + + } + + [Fact] + public async Task Should_Near_Text() + { + var client = Connect.Local(restPort: 8085, grpcPort: 50055); + + } +} diff --git a/_includes/code/csharp/WeaviateProject.Tests.csproj b/_includes/code/csharp/WeaviateProject.Tests.csproj new file mode 100644 index 000000000..303926820 --- /dev/null +++ b/_includes/code/csharp/WeaviateProject.Tests.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + true + + + + + + + + + + diff --git a/_includes/schema-delete-class.mdx b/_includes/schema-delete-class.mdx index 04d6b9453..1890fba39 100644 --- a/_includes/schema-delete-class.mdx +++ b/_includes/schema-delete-class.mdx @@ -4,6 +4,7 @@ import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBl import ManageCollectionsCode from '!!raw-loader!/_includes/code/howto/manage-data.collections.py'; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java'; import JavaV6Code from '!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java'; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/CollectionTests.cs"; You can delete any unwanted collection(s), along with the data that they contain. @@ -89,4 +90,12 @@ curl \ ``` + + + diff --git a/docs.sln b/docs.sln new file mode 100644 index 000000000..c5ead1f30 --- /dev/null +++ b/docs.sln @@ -0,0 +1,32 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_includes", "_includes", "{DE45C9AA-DBB3-91F8-540C-03A41DB425DA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code", "code", "{9186D019-DB3D-BB6C-536B-D636275C82A4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeaviateProject.Tests", "_includes\code\csharp\WeaviateProject.Tests.csproj", "{E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9186D019-DB3D-BB6C-536B-D636275C82A4} = {DE45C9AA-DBB3-91F8-540C-03A41DB425DA} + {E1A0B893-B9C7-B0BB-27A1-C94B4D04BC73} = {9186D019-DB3D-BB6C-536B-D636275C82A4} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E51A6D01-9E9C-4B44-BE15-9ECBB531729D} + EndGlobalSection +EndGlobal diff --git a/docs/weaviate/connections/connect-local.mdx b/docs/weaviate/connections/connect-local.mdx index ba5c11f6f..3d20e910d 100644 --- a/docs/weaviate/connections/connect-local.mdx +++ b/docs/weaviate/connections/connect-local.mdx @@ -17,6 +17,7 @@ import PyCodeV4 from "!!raw-loader!/_includes/code/connections/connect-python-v4 import TsCodeV3 from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts"; import JavaCode from "!!raw-loader!/_includes/code/connections/connect.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java"; +import CSharpCode from '!!raw-loader!/_includes/code/csharp/ConnectionTests.cs'; import ShellCode from "!!raw-loader!/_includes/code/connections/connect.sh"; import GoCode from "!!raw-loader!/_includes/code/connections/connect.go"; @@ -73,6 +74,14 @@ To connect to a local instance without authentication, follow these examples. language="java" /> + + + + + + :::tip Production ready collections @@ -152,6 +161,14 @@ For details, see: language="java" /> + + + ## Create a collection with a vectorizer diff --git a/docs/weaviate/manage-collections/vector-config.mdx b/docs/weaviate/manage-collections/vector-config.mdx index de2c6581a..ac9bc5735 100644 --- a/docs/weaviate/manage-collections/vector-config.mdx +++ b/docs/weaviate/manage-collections/vector-config.mdx @@ -13,6 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.collections.t import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.classes_test.go"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/CollectionTests.cs"; import VectorConfigSyntax from "/_includes/vector-config-syntax.mdx"; @@ -73,6 +74,14 @@ Collection level settings override default values and general configuration para language="java" /> + + + ## Specify vectorizer settings diff --git a/docs/weaviate/manage-objects/create.mdx b/docs/weaviate/manage-objects/create.mdx index e7f607945..07686f1c4 100644 --- a/docs/weaviate/manage-objects/create.mdx +++ b/docs/weaviate/manage-objects/create.mdx @@ -13,6 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.create.ts"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.create.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsCreateTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.create_test.go"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ObjectTests.cs"; The examples on this page demonstrate how to create individual objects in Weaviate. @@ -65,6 +66,14 @@ This example creates an object in the `JeopardyQuestion` collection. language="java" /> + + +
diff --git a/docs/weaviate/manage-objects/delete.mdx b/docs/weaviate/manage-objects/delete.mdx index 2506fee6c..bcd29c3c3 100644 --- a/docs/weaviate/manage-objects/delete.mdx +++ b/docs/weaviate/manage-objects/delete.mdx @@ -13,6 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.delete.ts"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.delete.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsDeleteTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.delete_test.go"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ObjectTests.cs"; import SkipLink from "/src/components/SkipValidationLink"; Weaviate allows object deletion by id or by a set of criteria. @@ -74,6 +75,14 @@ To delete by id, specify the collection name and the object id. startMarker="// START DeleteObject" endMarker="// END DeleteObject" language="java" + /> + + + diff --git a/docusaurus.config.js b/docusaurus.config.js index 6d86cdd8e..f8bdbf2cd 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -151,7 +151,7 @@ const config = { prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, - additionalLanguages: ["java"], + additionalLanguages: ['java', 'csharp'], }, docs: { sidebar: { From e92cc02b17f91d9dfa7658df9be5804a918d3d89 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 29 Jul 2025 10:31:16 +0200 Subject: [PATCH 02/18] Update docs --- _includes/code/csharp/ObjectTests.cs | 1 - _includes/code/csharp/SearchTests.cs | 36 ++++++++++++++++++++++++++-- docs/weaviate/search/basics.md | 16 +++++++++++++ docs/weaviate/search/similarity.md | 9 +++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/_includes/code/csharp/ObjectTests.cs b/_includes/code/csharp/ObjectTests.cs index e38e6a049..f3dec072e 100644 --- a/_includes/code/csharp/ObjectTests.cs +++ b/_includes/code/csharp/ObjectTests.cs @@ -35,7 +35,6 @@ public async Task Should_Import_Objects() public async Task Should_Delete_Objects() { var client = Connect.Local(restPort: 8085, grpcPort: 50055); - var collectionName = "Article"; if (await client.Collections.Exists(collectionName)) { diff --git a/_includes/code/csharp/SearchTests.cs b/_includes/code/csharp/SearchTests.cs index 21f6be53c..04f287ad4 100644 --- a/_includes/code/csharp/SearchTests.cs +++ b/_includes/code/csharp/SearchTests.cs @@ -3,22 +3,54 @@ using System; using System.Threading.Tasks; using Weaviate.Client.Models; +using System.Linq; namespace WeaviateProject.Tests; +public static class QueryConstants +{ + public const string NearTextQuery = "Weaviate"; +} + public class SearchTest { + readonly WeaviateClient client = Connect.Local(restPort: 8085, grpcPort: 50055); + [Fact] public async Task Should_Fetch_By_Id() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var collection = client.Collections.Use("JeopardyQuestion"); + var objectId = Guid.NewGuid(); + await collection.Data.Insert( + new + { + question = "This vector DB is OSS & supports automatic property type inference on import", + newProperty = 123 + }, + id: objectId + ); + // START FetchById + var obj = await collection.Query.FetchObjectByID(objectId); + Console.WriteLine($"Fetched object with ID: {obj.ID}"); + // END FetchById } [Fact] public async Task Should_Near_Text() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + // START GetNearText + var collection = client.Collections.Use("JeopardyQuestion"); + var queryResult = await collection.Query.NearText( + "animals in movies", + limit: 2, + metadata: MetadataOptions.Distance); + Console.WriteLine("Search Results:"); + foreach (var obj in queryResult.Objects) + { + Console.WriteLine($"Object: {obj.Properties})"); + } + // END GetNearText } } diff --git a/docs/weaviate/search/basics.md b/docs/weaviate/search/basics.md index 6f843981c..c60b8ad41 100644 --- a/docs/weaviate/search/basics.md +++ b/docs/weaviate/search/basics.md @@ -14,6 +14,7 @@ import TSCode from '!!raw-loader!/\_includes/code/howto/search.basics.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/mainpkg/search-basic_test.go'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/SearchBasicTest.java"; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/search/BasicSearchTest.java'; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchTests.cs"; With Weaviate you can query your data using [vector similarity search](./similarity.md), [keyword search](./bm25.md), or a mix of both with [hybrid search](./hybrid.md). You can control what object [properties](#specify-object-properties) and [metadata](#retrieve-metadata-values) to return. @@ -95,6 +96,21 @@ Specify the information that you want your query to return. You can return objec
+## Fetch objects by ID + +Fetch an object by its UUID: + + + + + + + ## `limit` returned objects Use `limit` to set a fixed maximum number of objects to return. diff --git a/docs/weaviate/search/similarity.md b/docs/weaviate/search/similarity.md index 91f04b1f4..3f2153104 100644 --- a/docs/weaviate/search/similarity.md +++ b/docs/weaviate/search/similarity.md @@ -14,6 +14,7 @@ import TSCode from '!!raw-loader!/\_includes/code/howto/search.similarity.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/mainpkg/search-similarity_test.go'; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/search/VectorSearchTest.java'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/SearchSimilarityTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchTests.cs"; Vector search returns the objects with most similar vectors to that of the query. @@ -70,6 +71,14 @@ Use the [`Near Text`](../api/graphql/search-operators.md#neartext) operator to f language="graphql" /> + + +
From 266bfafb16140244524be163b16a24057b7664a7 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 29 Jul 2025 12:23:10 +0200 Subject: [PATCH 03/18] Update docs --- _includes/code/csharp/CollectionTests.cs | 15 +++++----- _includes/code/csharp/ConnectionTests.cs | 29 +++++++++++++++++++- _includes/code/csharp/ObjectTests.cs | 4 +-- _includes/code/csharp/SearchTests.cs | 4 +-- docs/weaviate/connections/connect-custom.mdx | 9 ++++++ 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/_includes/code/csharp/CollectionTests.cs b/_includes/code/csharp/CollectionTests.cs index 0934dbd15..814d3edb5 100644 --- a/_includes/code/csharp/CollectionTests.cs +++ b/_includes/code/csharp/CollectionTests.cs @@ -11,7 +11,7 @@ public class CollectionTest [Fact] public async Task Should_Create_Collection() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); // START BasicCreateCollection var collectionName = "Article"; // END BasicCreateCollection @@ -37,7 +37,7 @@ public async Task Should_Create_Collection() [Fact] public async Task Should_Create_Collection_With_Properties() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); // START CreateCollectionWithProperties var collectionName = "Article"; // END CreateCollectionWithProperties @@ -53,7 +53,8 @@ public async Task Should_Create_Collection_With_Properties() { Name = collectionName, Description = "something", - Properties = [Property.Int("number_property"),Property.Text("test_property")], + Properties = [Property.Int("number_property"), Property.Text("test_property")], + // Properties = [.. Property.FromCollection()], // For dynamic properties, you can use the FromCollection method }; var collection = await client.Collections.Create(articleCollection); @@ -64,7 +65,7 @@ public async Task Should_Create_Collection_With_Properties() [Fact] public async Task Should_Create_Collection_With_Vectorizer() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); // START CreateCollectionWithVectorizer var collectionName = "Article"; // END CreateCollectionWithVectorizer @@ -80,8 +81,8 @@ public async Task Should_Create_Collection_With_Vectorizer() { Name = collectionName, Description = "something", - Properties = [Property.Int("number_property"),Property.Text("test_property")], - VectorConfig = new VectorConfig("vector_name", new Vectorizer.Text2VecContextionary()) + Properties = [Property.Int("number_property"), Property.Text("test_property")], + VectorConfig = new VectorConfig("vector_name", new Vectorizer.Text2VecContextionary(), new VectorIndex.HNSW()) }; var collection = await client.Collections.Create(articleCollection); @@ -92,7 +93,7 @@ public async Task Should_Create_Collection_With_Vectorizer() [Fact] public async Task Should_Delete_Collection() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); var collectionName = "Article"; // Ensure the collection exists before attempting to delete it diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs index ed158de63..a65d4d1b9 100644 --- a/_includes/code/csharp/ConnectionTests.cs +++ b/_includes/code/csharp/ConnectionTests.cs @@ -11,7 +11,7 @@ public class ConnectionTest public async Task Should_Connect_To_Weaviate() { // START LocalNoAuth - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); // END LocalNoAuth // try // { @@ -24,4 +24,31 @@ public async Task Should_Connect_To_Weaviate() // Assert.True(false, $"Connection failed: {ex.Message}"); // } } + + [Fact] + public async Task Should_Custom_Connect_To_Weaviate() + { + // START CustomConnect + var config = new ClientConfiguration( + RestAddress: "localhost", + GrpcAddress: "localhost", + RestPort: 8080, + GrpcPort: 50051, + UseSsl: false, + ApiKey: null + ); + + var client = new WeaviateClient(config); + // END CustomConnect + // try + // { + // var meta = await client.GetMeta(); + // Assert.NotNull(meta); + // Assert.NotNull(client); + // } + // catch (Exception ex) + // { + // Assert.True(false, $"Connection failed: {ex.Message}"); + // } + } } diff --git a/_includes/code/csharp/ObjectTests.cs b/_includes/code/csharp/ObjectTests.cs index f3dec072e..ac9323355 100644 --- a/_includes/code/csharp/ObjectTests.cs +++ b/_includes/code/csharp/ObjectTests.cs @@ -14,7 +14,7 @@ public class ObjectTest [Fact] public async Task Should_Import_Objects() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); // START CreateObject var collectionClient = client.Collections.Use(collectionName); @@ -34,7 +34,7 @@ public async Task Should_Import_Objects() [Fact] public async Task Should_Delete_Objects() { - var client = Connect.Local(restPort: 8085, grpcPort: 50055); + var client = Connect.Local(restPort: 8080, grpcPort: 50051); if (await client.Collections.Exists(collectionName)) { diff --git a/_includes/code/csharp/SearchTests.cs b/_includes/code/csharp/SearchTests.cs index 04f287ad4..492e05390 100644 --- a/_includes/code/csharp/SearchTests.cs +++ b/_includes/code/csharp/SearchTests.cs @@ -14,7 +14,7 @@ public static class QueryConstants public class SearchTest { - readonly WeaviateClient client = Connect.Local(restPort: 8085, grpcPort: 50055); + readonly WeaviateClient client = Connect.Local(restPort: 8080, grpcPort: 50051); [Fact] public async Task Should_Fetch_By_Id() @@ -43,7 +43,7 @@ public async Task Should_Near_Text() var collection = client.Collections.Use("JeopardyQuestion"); var queryResult = await collection.Query.NearText( "animals in movies", - limit: 2, + limit: 1, metadata: MetadataOptions.Distance); Console.WriteLine("Search Results:"); diff --git a/docs/weaviate/connections/connect-custom.mdx b/docs/weaviate/connections/connect-custom.mdx index a3bc78956..1c6adefcd 100644 --- a/docs/weaviate/connections/connect-custom.mdx +++ b/docs/weaviate/connections/connect-custom.mdx @@ -12,6 +12,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl import PyCodeV4 from "!!raw-loader!/_includes/code/connections/connect-python-v4.py"; import TsCodeV3 from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java"; +import CSharpCode from '!!raw-loader!/_includes/code/csharp/ConnectionTests.cs'; The [Python Client v4](/weaviate/client-libraries/python) and the [TypeScript Client v3](../client-libraries/typescript/index.mdx) provide helper methods for common connection types. They also provide custom methods for when you need additional connection configuration. @@ -42,6 +43,14 @@ If you are using one of the other clients, the standard connection methods are c language="java" /> + + + ## Environment variables From 7c1527a5cc731445048ccdf1704b8a03e1ca17be Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:40:06 +0200 Subject: [PATCH 04/18] Update docs --- _includes/code/csharp/CollectionTests.cs | 8 +- _includes/code/csharp/ConnectionTests.cs | 166 ++++++++++++++---- _includes/code/csharp/ObjectTests.cs | 4 +- _includes/code/csharp/SearchTests.cs | 4 +- .../code/csharp/WeaviateProject.Tests.csproj | 2 +- 5 files changed, 140 insertions(+), 44 deletions(-) diff --git a/_includes/code/csharp/CollectionTests.cs b/_includes/code/csharp/CollectionTests.cs index 814d3edb5..f028e6481 100644 --- a/_includes/code/csharp/CollectionTests.cs +++ b/_includes/code/csharp/CollectionTests.cs @@ -8,7 +8,7 @@ namespace WeaviateProject.Tests; public class CollectionTest { - [Fact] + // [Fact] public async Task Should_Create_Collection() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); @@ -34,7 +34,7 @@ public async Task Should_Create_Collection() Console.WriteLine($"Successfully created collection: '{collectionName}'"); } - [Fact] + // [Fact] public async Task Should_Create_Collection_With_Properties() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); @@ -62,7 +62,7 @@ public async Task Should_Create_Collection_With_Properties() Console.WriteLine($"Successfully created collection: '{collectionName}'"); } - [Fact] + // [Fact] public async Task Should_Create_Collection_With_Vectorizer() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); @@ -90,7 +90,7 @@ public async Task Should_Create_Collection_With_Vectorizer() Console.WriteLine($"Successfully created collection: '{collectionName}'"); } - [Fact] + // [Fact] public async Task Should_Delete_Collection() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs index a65d4d1b9..b63dee49c 100644 --- a/_includes/code/csharp/ConnectionTests.cs +++ b/_includes/code/csharp/ConnectionTests.cs @@ -1,54 +1,150 @@ -using Xunit; using Weaviate.Client; using System; using System.Threading.Tasks; +using Xunit; namespace WeaviateProject.Tests; -public class ConnectionTest +public class ConnectionSnippetsTest { + /// + /// Test for local connection with a custom URL and port. + /// [Fact] - public async Task Should_Connect_To_Weaviate() + public async Task Should_Connect_With_Custom_URL() { - // START LocalNoAuth - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - // END LocalNoAuth - // try - // { - // var meta = await client.GetMeta(); - // Assert.NotNull(meta); - // Assert.NotNull(client); - // } - // catch (Exception ex) - // { - // Assert.True(false, $"Connection failed: {ex.Message}"); - // } + // START CustomURL + // The Connect.Local() method defaults to "localhost". + // For a different host, you must use a custom configuration. + var config = new ClientConfiguration( + RestAddress: "127.0.0.1", + GrpcAddress: "127.0.0.1", + RestPort: 8080, + GrpcPort: 50051 + ); + var client = new WeaviateClient(config); + // END CustomURL + + try + { + var meta = await client.GetMeta(); + Assert.False(string.IsNullOrEmpty(meta.Version.ToString())); + } + catch (Exception ex) + { + Assert.Fail($"Connection failed: {ex.Message}"); + } } + /// + /// Test for a fully custom connection, typically for a cloud instance. + /// [Fact] - public async Task Should_Custom_Connect_To_Weaviate() + public async Task Should_Perform_Custom_Connection_With_ApiKey() { // START CustomConnect - var config = new ClientConfiguration( - RestAddress: "localhost", - GrpcAddress: "localhost", - RestPort: 8080, - GrpcPort: 50051, - UseSsl: false, - ApiKey: null + // START ConnectWithApiKeyExample + var httpHost = Environment.GetEnvironmentVariable("WEAVIATE_HTTP_HOST"); + var grpcHost = Environment.GetEnvironmentVariable("WEAVIATE_GRPC_HOST"); + var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + + var config = new ClientConfiguration( + RestAddress: httpHost, // Hostname for the HTTP API connection + RestPort: 443, // Default is 80, WCD uses 443 + UseSsl: true, // Whether to use https (secure) for the HTTP API connection + GrpcAddress: grpcHost, // Hostname for the gRPC API connection + GrpcPort: 443, // Default is 50051, WCD uses 443 + ApiKey: weaviateApiKey // API key for authentication ); - var client = new WeaviateClient(config); // END CustomConnect - // try - // { - // var meta = await client.GetMeta(); - // Assert.NotNull(meta); - // Assert.NotNull(client); - // } - // catch (Exception ex) - // { - // Assert.True(false, $"Connection failed: {ex.Message}"); - // } + // END ConnectWithApiKeyExample + + try + { + var meta = await client.GetMeta(); + Assert.False(string.IsNullOrEmpty(meta.Version.ToString())); + } + catch (Exception ex) + { + Assert.Fail($"Connection failed: {ex.Message}"); + } + } + + /// + /// Test for connecting to Weaviate Cloud (WCD). + /// + [Fact] + public async Task Should_Connect_To_WCD_With_Api_Key() + { + // START APIKeyWCD + var weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL"); + var wcdApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + + var client = Connect.Cloud( + restEndpoint: weaviateUrl, + apiKey: wcdApiKey + ); + // END APIKeyWCD + + try + { + var meta = await client.GetMeta(); + Assert.False(string.IsNullOrEmpty(meta.Version.ToString())); + } + catch (Exception ex) + { + Assert.Fail($"Connection failed: {ex.Message}"); + } + } + + /// + /// Test for a default local connection without authentication. + /// + [Fact] + public async Task Should_Connect_Locally_Without_Auth() + { + // START LocalNoAuth + var client = Connect.Local(); + // END LocalNoAuth + + try + { + var meta = await client.GetMeta(); + Assert.False(string.IsNullOrEmpty(meta.Version.ToString())); + } + catch (Exception ex) + { + Assert.Fail($"Connection failed: {ex.Message}"); + } + } + + /// + /// Test for a local connection using an API key and non-default ports. + /// + // TODO[g-despot]: Broken for some reason + //[Fact] + public async Task Should_Connect_Locally_With_Auth() + { + // START LocalAuth + var localApiKey = Environment.GetEnvironmentVariable("WEAVIATE_LOCAL_API_KEY"); + + var client = Connect.Local( + restPort: 8099, + grpcPort: 50052, + useSsl: true, + apiKey: localApiKey + ); + // END LocalAuth + + try + { + var meta = await client.GetMeta(); + Assert.False(string.IsNullOrEmpty(meta.Version.ToString())); + } + catch (Exception ex) + { + Assert.Fail($"Connection failed: {ex.Message}"); + } } } diff --git a/_includes/code/csharp/ObjectTests.cs b/_includes/code/csharp/ObjectTests.cs index ac9323355..adf8ec4bc 100644 --- a/_includes/code/csharp/ObjectTests.cs +++ b/_includes/code/csharp/ObjectTests.cs @@ -11,7 +11,7 @@ public class ObjectTest readonly Guid objectId = Guid.NewGuid(); readonly string collectionName = "Jeopardy"; - [Fact] + // [Fact] public async Task Should_Import_Objects() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); @@ -31,7 +31,7 @@ public async Task Should_Import_Objects() Console.WriteLine($"Successfully created collection: '{collectionName}'"); } - [Fact] + // [Fact] public async Task Should_Delete_Objects() { var client = Connect.Local(restPort: 8080, grpcPort: 50051); diff --git a/_includes/code/csharp/SearchTests.cs b/_includes/code/csharp/SearchTests.cs index 492e05390..1a93406cd 100644 --- a/_includes/code/csharp/SearchTests.cs +++ b/_includes/code/csharp/SearchTests.cs @@ -16,7 +16,7 @@ public class SearchTest { readonly WeaviateClient client = Connect.Local(restPort: 8080, grpcPort: 50051); - [Fact] + // [Fact] public async Task Should_Fetch_By_Id() { var collection = client.Collections.Use("JeopardyQuestion"); @@ -36,7 +36,7 @@ await collection.Data.Insert( // END FetchById } - [Fact] + // [Fact] public async Task Should_Near_Text() { // START GetNearText diff --git a/_includes/code/csharp/WeaviateProject.Tests.csproj b/_includes/code/csharp/WeaviateProject.Tests.csproj index 303926820..accde3e72 100644 --- a/_includes/code/csharp/WeaviateProject.Tests.csproj +++ b/_includes/code/csharp/WeaviateProject.Tests.csproj @@ -9,7 +9,7 @@ - + From 07bb34a40974218f92667f93afc3e60dce7bbe9f Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:37:13 +0200 Subject: [PATCH 05/18] New C# code --- _includes/code/csharp/ConnectionTests.cs | 2 - .../code/csharp/ManageCollectionsTests.cs | 499 ++++++++++++++++++ docs/weaviate/connections/connect-cloud.mdx | 9 + docs/weaviate/connections/connect-local.mdx | 16 + .../Documentation/FilteredTextBlock.js | 4 + 5 files changed, 528 insertions(+), 2 deletions(-) create mode 100644 _includes/code/csharp/ManageCollectionsTests.cs diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs index b63dee49c..f192a82ea 100644 --- a/_includes/code/csharp/ConnectionTests.cs +++ b/_includes/code/csharp/ConnectionTests.cs @@ -43,7 +43,6 @@ public async Task Should_Connect_With_Custom_URL() public async Task Should_Perform_Custom_Connection_With_ApiKey() { // START CustomConnect - // START ConnectWithApiKeyExample var httpHost = Environment.GetEnvironmentVariable("WEAVIATE_HTTP_HOST"); var grpcHost = Environment.GetEnvironmentVariable("WEAVIATE_GRPC_HOST"); var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); @@ -58,7 +57,6 @@ public async Task Should_Perform_Custom_Connection_With_ApiKey() ); var client = new WeaviateClient(config); // END CustomConnect - // END ConnectWithApiKeyExample try { diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTests.cs new file mode 100644 index 000000000..01e001929 --- /dev/null +++ b/_includes/code/csharp/ManageCollectionsTests.cs @@ -0,0 +1,499 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; + +public class ManageDataTests : IAsyncLifetime +{ + private readonly WeaviateClient weaviate; + private readonly List _collectionNamesToDelete = new List(); + + public ManageDataTests() + { + weaviate = new WeaviateClient( + new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 } + ); + } + + private string AddTestCollection(string name) + { + _collectionNamesToDelete.Add(name); + return name; + } + + public Task InitializeAsync() => Task.CompletedTask; + + public async Task DisposeAsync() + { + foreach (string name in _collectionNamesToDelete) + { + await weaviate.Collections.Delete(name); + } + } + + [Fact] + public async Task CreateBasicCollection() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START BasicCreateCollection + Collection articleCollection = new Collection { Name = collectionName }; + await weaviate.Collections.Create(articleCollection); + // END BasicCreateCollection + + bool exists = await weaviate.Collections.Exists(collectionName); + Assert.True(exists); + } + + [Fact] + public async Task CreateCollectionWithProperties() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START CreateCollectionWithProperties + Collection articleCollection = new Collection + { + Name = collectionName, + Properties = new List + { + Property.Text("title"), + Property.Text("body"), + } + }; + await weaviate.Collections.Create(articleCollection); + // END CreateCollectionWithProperties + + Collection collection = await weaviate.Collections.Export(collectionName); + Assert.NotNull(collection); + Assert.Equal(2, collection.Properties.Count); + } + + [Fact] + public async Task CreateCollectionWithVectorizer() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START Vectorizer + Collection articleCollection = new Collection + { + Name = collectionName, + VectorConfig = Configure.Vectors.Text2VecOpenAI("default").New(), + Properties = new List + { + Property.Text("title"), + Property.Text("body"), + } + }; + await weaviate.Collections.Create(articleCollection); + // END Vectorizer + + Collection collection = await weaviate.Collections.Export(collectionName); + Assert.NotNull(collection.VectorConfig); + Assert.Equal("text2vec-openai", collection.VectorConfig["default"].Vectorizer.Identifier); + } + + [Fact] + public async Task CreateCollectionWithNamedVectors() + { + string collectionName = AddTestCollection("ArticleNV"); + await weaviate.Collections.Delete(collectionName); + + // START BasicNamedVectors + Collection articleCollection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList + { + // TODO[g-despot]: How to specify source properties + //Configure.Vectors.Text2VecCohere(sourceProperties: new[] { "title" }).New("title"), + //Configure.Vectors.Text2VecOpenAI(sourceProperties: new[] { "title", "country" }).New("title_country"), + Configure.Vectors.SelfProvided("default"), + }, + Properties = new List + { + Property.Text("title"), + Property.Text("country"), + } + }; + await weaviate.Collections.Create(articleCollection); + // END BasicNamedVectors + + Collection collection = await weaviate.Collections.Export(collectionName); + Assert.Equal(1, collection.VectorConfig.Count); + // Assert.Equal(new[] { "title" }, collection.VectorConfig["title"].Vectorizer.SourceProperties); + } + + [Fact] + public async Task SetVectorIndexType() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START SetVectorIndexType + Collection articleCollection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList + { + new VectorConfig( + name: "default", + vectorizer: new Vectorizer.Text2VecOpenAI(), + vectorIndexConfig: new VectorIndex.HNSW() + ) + }, + Properties = new List + { + Property.Text("title"), + Property.Text("body"), + } + }; + await weaviate.Collections.Create(articleCollection); + // END SetVectorIndexType + + Collection collection = await weaviate.Collections.Export(collectionName); + Assert.IsType(collection.VectorConfig["default"].VectorIndexConfig); + } + + [Fact] + public async Task SetVectorIndexParams() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START SetVectorIndexParams + Collection articleCollection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList + { + new VectorConfig( + name: "default", + vectorizer: new Vectorizer.Text2VecOpenAI(), + vectorIndexConfig: new VectorIndex.HNSW + { + EfConstruction = 300, + Distance = VectorIndexConfig.VectorDistance.Cosine, + FilterStrategy = VectorIndexConfig.VectorIndexFilterStrategy.Sweeping + } + ) + } + }; + await weaviate.Collections.Create(articleCollection); + // END SetVectorIndexParams + + Collection collection = await weaviate.Collections.Export(collectionName); + VectorIndex.HNSW hnswConfig = Assert.IsType(collection.VectorConfig["default"].VectorIndexConfig); + Assert.Equal(300, hnswConfig.EfConstruction); + } + + [Fact] + public async Task SetInvertedIndexParams() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START SetInvertedIndexParams + Collection articleCollection = new Collection + { + Name = collectionName, + Properties = new List + { + Property.Text("title", indexFilterable: true, indexSearchable: true), + Property.Text("chunk", indexFilterable: true, indexSearchable: true), + Property.Int("chunk_number", indexRangeFilters: true), + }, + InvertedIndexConfig = new InvertedIndexConfig + { + Bm25 = new BM25Config { B = 0.7f, K1 = 1.25f }, + IndexNullState = true, + IndexPropertyLength = true, + IndexTimestamps = true, + } + }; + await weaviate.Collections.Create(articleCollection); + // END SetInvertedIndexParams + + Collection collection = await weaviate.Collections.Export(collectionName); + Assert.Equal(0.7f, collection.InvertedIndexConfig.Bm25.B); + Assert.Equal(1.25f, collection.InvertedIndexConfig.Bm25.K1); + } + + [Fact] + public async Task SetAndReadModules() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START SetReranker + Collection articleReranker = new Collection + { + Name = collectionName, + VectorConfig = Configure.Vectors.Text2VecOpenAI().New(), + RerankerConfig = new Reranker.Cohere() + }; + await weaviate.Collections.Create(articleReranker); + // END SetReranker + + Collection collectionConfig = await weaviate.Collections.Export(collectionName); + Assert.Equal("reranker-cohere", (collectionConfig.RerankerConfig as Reranker.Cohere)?.Type); + + await weaviate.Collections.Delete(collectionName); + + // START SetGenerative + Collection articleGenerative = new Collection + { + Name = collectionName, + VectorConfig = Configure.Vectors.Text2VecOpenAI().New(), + //TODO[g-despot]: Missing model parameter for generative OpenAIConfig + GenerativeConfig = new Generative.OpenAIConfig() + }; + await weaviate.Collections.Create(articleGenerative); + // END SetGenerative + + collectionConfig = await weaviate.Collections.Export(collectionName); + Assert.Equal("generative-openai", (collectionConfig.GenerativeConfig as Generative.OpenAIConfig)?.Type); + } + + [Fact] + public async Task UpdateModules() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + Collection initialCollection = new Collection + { + Name = collectionName, + VectorConfig = Configure.Vectors.Text2VecOpenAI().New(), + RerankerConfig = new Reranker.VoyageAI() + }; + await weaviate.Collections.Create(initialCollection); + + // START UpdateReranker + CollectionClient collectionToUpdate = weaviate.Collections.Use(collectionName); + await collectionToUpdate.Config.Update(c => + { + c.RerankerConfig = new Reranker.Cohere(); + }); + // END UpdateReranker + + Collection config = await weaviate.Collections.Export(collectionName); + Assert.Equal("reranker-cohere", (config.RerankerConfig as Reranker.Cohere)?.Type); + } + + [Fact] + public async Task ConfigureModuleSettings() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START ModuleSettings + Collection articleCollection = new Collection + { + Name = collectionName, + // highlight-start + VectorConfig = new VectorConfigList + { + new VectorConfig( + name: "default", + vectorizer: new Vectorizer.Text2VecCohere + { + Model = "embed-multilingual-v2.0", + VectorizeCollectionName = true + } + ) + } + // highlight-end + }; + await weaviate.Collections.Create(articleCollection); + // END ModuleSettings + + Collection config = await weaviate.Collections.Export(collectionName); + Vectorizer.Text2VecCohere cohereVectorizer = Assert.IsType(config.VectorConfig["default"].Vectorizer); + Assert.Equal("embed-multilingual-v2.0", cohereVectorizer.Model); + } + + [Fact] + public async Task ConfigurePropertyModuleSettings() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START PropModuleSettings + Collection articleCollection = new Collection + { + Name = collectionName, + VectorConfig = Configure.Vectors.Text2VecCohere().New(), + Properties = new List + { + Property.Text( + "title", + // TODO[g-despot]: Missing vectorizePropertyName + // vectorizePropertyName: true, + tokenization: PropertyTokenization.Lowercase + ), + Property.Text( + "body", + // TODO[g-despot]: Missing vectorizePropertyName + // skipVectorization: true, + tokenization: PropertyTokenization.Whitespace + ), + } + }; + await weaviate.Collections.Create(articleCollection); + // END PropModuleSettings + + // START AddNamedVectors + CollectionClient articles = weaviate.Collections.Use(collectionName); + // TODO[g-despot]: AddVector throws error + // await articles.Config.AddVector( + // TODO[g-despot]: Missing sourceProperties + // Configure.Vectors.Text2VecCohere(sourceProperties: new[] { "body" }).New("body_vector") + // Configure.Vectors.Text2VecCohere().New("body_vector") + // ); + // END AddNamedVectors + + Collection config = await weaviate.Collections.Export(collectionName); + Assert.Equal(1, config.VectorConfig.Count); + //Assert.NotNull(config.VectorConfig["body_vector"]); + } + + [Fact] + public async Task SetDistanceMetric() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START DistanceMetric + Collection articleCollection = new Collection + { + Name = collectionName, + // highlight-start + VectorConfig = new VectorConfigList + { + new VectorConfig( + name: "default", + vectorizer: new Vectorizer.Text2VecOpenAI(), + vectorIndexConfig: new VectorIndex.HNSW + { + Distance = VectorIndexConfig.VectorDistance.Cosine + } + ) + } + // highlight-end + }; + await weaviate.Collections.Create(articleCollection); + // END DistanceMetric + + Collection config = await weaviate.Collections.Export(collectionName); + VectorIndex.HNSW hnswConfig = Assert.IsType(config.VectorConfig["default"].VectorIndexConfig); + Assert.Equal(VectorIndexConfig.VectorDistance.Cosine, hnswConfig.Distance); + } + + [Fact] + public async Task ConfigureReplicationAndSharding() + { + // --- Replication Part --- + // Connect to the Weaviate instance configured for replication tests on port 8180 + WeaviateClient replicationClient = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8180 }); + string replicationCollectionName = AddTestCollection("ArticleReplication"); + await replicationClient.Collections.Delete(replicationCollectionName); + + // START ReplicationSettings + Collection replCollection = new Collection + { + Name = replicationCollectionName, + ReplicationConfig = new ReplicationConfig { Factor = 3 } + }; + await replicationClient.Collections.Create(replCollection); + // END ReplicationSettings + + Collection config = await replicationClient.Collections.Export(replicationCollectionName); + Assert.Equal(3, config.ReplicationConfig.Factor); + await replicationClient.Collections.Delete(replicationCollectionName); // Clean up using the replication client + + + // --- Sharding Part --- + // Use the default client for sharding tests + string shardingCollectionName = AddTestCollection("ArticleSharding"); + await weaviate.Collections.Delete(shardingCollectionName); + + // START ShardingSettings + Collection shardCollection = new Collection + { + Name = shardingCollectionName, + ShardingConfig = new ShardingConfig + { + VirtualPerPhysical = 128, + DesiredCount = 1, + DesiredVirtualCount = 128, + } + }; + await weaviate.Collections.Create(shardCollection); + // END ShardingSettings + + config = await weaviate.Collections.Export(shardingCollectionName); + Assert.Equal(128, config.ShardingConfig.VirtualPerPhysical); + } + + [Fact] + public async Task ConfigureMultiTenancyAndProperties() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // START Multi-tenancy + Collection mtCollection = new Collection + { + Name = collectionName, + MultiTenancyConfig = new MultiTenancyConfig { Enabled = true } + }; + await weaviate.Collections.Create(mtCollection); + // END Multi-tenancy + + Collection config = await weaviate.Collections.Export(collectionName); + Assert.True(config.MultiTenancyConfig.Enabled); + + // START AddProp + CollectionClient articles = weaviate.Collections.Use(collectionName); + // TODO[g-despot]: AddProperty is internal + // await articles.Config.AddProperty(Property.Text("body")); + // END AddProp + + config = await weaviate.Collections.Export(collectionName); + // Assert.Contains(config.Properties, p => p.Name == "body"); + } + + [Fact] + public async Task ReadAndDeleteCollections() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + await weaviate.Collections.Create(new Collection { Name = collectionName }); + + // START ReadOneCollection + CollectionClient articlesClient = weaviate.Collections.Use(collectionName); + Collection articlesConfig = await articlesClient.Get(); + Console.WriteLine(articlesConfig.Name); + // END ReadOneCollection + Assert.Equal(collectionName, articlesConfig.Name); + + // START ReadAllCollections + await foreach (Collection collection in weaviate.Collections.List()) + { + Console.WriteLine(collection.Name); + } + // END ReadAllCollections + + // START DeleteCollection + await weaviate.Collections.Delete(collectionName); + // END DeleteCollection + + bool exists = await weaviate.Collections.Exists(collectionName); + Assert.False(exists); + } +} \ No newline at end of file diff --git a/docs/weaviate/connections/connect-cloud.mdx b/docs/weaviate/connections/connect-cloud.mdx index 3bc9e241a..b39d3fc3e 100644 --- a/docs/weaviate/connections/connect-cloud.mdx +++ b/docs/weaviate/connections/connect-cloud.mdx @@ -15,6 +15,7 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Conne import JavaCode from "!!raw-loader!/_includes/code/connections/connect.java"; import ShellCode from "!!raw-loader!/_includes/code/connections/connect.sh"; import GoCode from "!!raw-loader!/_includes/code/connections/connect.go"; +import CSharpCode from '!!raw-loader!/_includes/code/csharp/ConnectionTests.cs'; Follow these steps to connect to a [Weaviate Cloud (WCD)](https://console.weaviate.cloud/) instance. @@ -101,6 +102,14 @@ import HostnameWarning from "/_includes/wcs/hostname-warning.mdx"; /> + + + + + + + + + input.replace(/^ /, ''); + break; case 'java': // remove leading indent of 4 spaces format = (input) => input.replace(/^ /, ''); From 25587a9c27f8a589eee5e47b361a457764f25d5a Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Wed, 20 Aug 2025 07:50:25 +0200 Subject: [PATCH 06/18] Update docs --- .../code/csharp/ManageCollectionsTests.cs | 65 +++++++ _includes/schema-delete-class.mdx | 2 +- .../collection-operations.mdx | 159 ++++++++++++++---- 3 files changed, 194 insertions(+), 32 deletions(-) diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTests.cs index 01e001929..a8678e077 100644 --- a/_includes/code/csharp/ManageCollectionsTests.cs +++ b/_includes/code/csharp/ManageCollectionsTests.cs @@ -468,6 +468,71 @@ public async Task ConfigureMultiTenancyAndProperties() // Assert.Contains(config.Properties, p => p.Name == "body"); } + [Fact] + public async Task Should_Update_Collection_Configuration() + { + // Arrange: Create a collection with initial settings to be updated + string collectionName = "ArticleForUpdate"; + await weaviate.Collections.Delete(collectionName); // Ensure clean state + + Collection initialCollection = new Collection + { + Name = collectionName, + Description = "An old collection description.", + InvertedIndexConfig = new InvertedIndexConfig + { + Bm25 = new BM25Config { K1 = 1.2f } + }, + Properties = + [ + Property.Text( + "title" + ), + ], + VectorConfig = new VectorConfigList + { + new VectorConfig( + "default", + new Vectorizer.Text2VecOpenAI(), + new VectorIndex.HNSW { FilterStrategy = VectorIndexConfig.VectorIndexFilterStrategy.Sweeping } + ) + }, + ReplicationConfig = new ReplicationConfig() + }; + await weaviate.Collections.Create(initialCollection); + + CollectionClient articles = weaviate.Collections.Use(collectionName); + + // Act: Update the collection + // START UpdateCollection + await articles.Config.Update(c => + { + c.Description = "An updated collection description."; + // TODO[g-despot]: Updating property descriptions is missing + c.InvertedIndexConfig.Bm25.K1 = 1.5f; + + VectorConfigUpdate vectorConfig = c.VectorConfig["default"]; + vectorConfig.VectorIndexConfig.UpdateHNSW(vic => + { + vic.FilterStrategy = VectorIndexConfig.VectorIndexFilterStrategy.Acorn; + }); + + c.ReplicationConfig.DeletionStrategy = DeletionStrategy.TimeBasedResolution; + }); + // END UpdateCollection + + // Assert: Fetch the updated config and verify changes + Collection newConfig = await weaviate.Collections.Export(collectionName); + + Assert.Equal("An updated collection description.", newConfig.Description); + Assert.Equal(1.5f, newConfig.InvertedIndexConfig.Bm25.K1); + + VectorIndex.HNSW hnswConfig = Assert.IsType(newConfig.VectorConfig["default"].VectorIndexConfig); + Assert.Equal(VectorIndexConfig.VectorIndexFilterStrategy.Acorn, hnswConfig.FilterStrategy); + + Assert.Equal(DeletionStrategy.TimeBasedResolution, newConfig.ReplicationConfig.DeletionStrategy); + } + [Fact] public async Task ReadAndDeleteCollections() { diff --git a/_includes/schema-delete-class.mdx b/_includes/schema-delete-class.mdx index 1890fba39..cf35d6c12 100644 --- a/_includes/schema-delete-class.mdx +++ b/_includes/schema-delete-class.mdx @@ -4,7 +4,7 @@ import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBl import ManageCollectionsCode from '!!raw-loader!/_includes/code/howto/manage-data.collections.py'; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java'; import JavaV6Code from '!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java'; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/CollectionTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTests.cs"; You can delete any unwanted collection(s), along with the data that they contain. diff --git a/docs/weaviate/manage-collections/collection-operations.mdx b/docs/weaviate/manage-collections/collection-operations.mdx index b40e7d70d..f6189f3ee 100644 --- a/docs/weaviate/manage-collections/collection-operations.mdx +++ b/docs/weaviate/manage-collections/collection-operations.mdx @@ -14,7 +14,7 @@ import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/w import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; import JavaReplicationCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.replication.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.classes_test.go"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/CollectionTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTests.cs"; Every object in Weaviate belongs to exactly one collection. Use the examples on this page to manage your collections. @@ -28,7 +28,7 @@ import VectorConfigSyntax from "/_includes/vector-config-syntax.mdx"; ## Create a collection -To create a collection, specify at least the collection name. If you don't specify any properties, [`auto-schema`](../config-refs/collections.mdx#auto-schema) creates them. +To create a collection, specify at least the collection name. If you don't specify any properties, [`auto-schema`](https://www.google.com/search?q=../config-refs/collections.mdx%23auto-schema) creates them. import InitialCaps from "/_includes/schemas/initial-capitalization.md"; @@ -53,10 +53,10 @@ import InitialCaps from "/_includes/schemas/initial-capitalization.md"; @@ -104,19 +104,19 @@ import CollectionsCountLimit from '/_includes/collections-count-limit.mdx' Properties are the data fields in your collection. Each property has a name and a data type.
- - Additional information - + +Additional information + Use properties to configure additional parameters such as data type, index characteristics, or tokenization. For details, see: -- [References: Configuration: Schema](/weaviate/config-refs/collections.mdx) -- +- [References: Configuration: Schema](https://www.google.com/search?q=/weaviate/config-refs/collections.mdx) +- API References: REST: Schema -- [Available data types](../config-refs/datatypes.md) +- [Available data types](https://www.google.com/search?q=../config-refs/datatypes.md)
@@ -216,11 +216,19 @@ Specify a `vectorizer` for a collection that will generate vector embeddings whe language="java" />
+ + + :::info Vectorizer configuration -Find out more about the vectorizer and vector index configuration in [Manage collections: Vectorizer and vector index](./vector-config.mdx). +Find out more about the vectorizer and vector index configuration in [Manage collections: Vectorizer and vector index](https://www.google.com/search?q=./vector-config.mdx). ::: @@ -228,7 +236,7 @@ Find out more about the vectorizer and vector index configuration in [Manage col By default, Weaviate creates missing collections and missing properties. When you configure collections manually, you have more precise control of the collection settings. -To disable [`auto-schema`](../config-refs/collections.mdx#auto-schema) set `AUTOSCHEMA_ENABLED: 'false'` in your system configuration file. +To disable [`auto-schema`](https://www.google.com/search?q=../config-refs/collections.mdx%23auto-schema) set `AUTOSCHEMA_ENABLED: 'false'` in your system configuration file. ## Check if a collection exists @@ -298,10 +306,18 @@ Retrieve a collection definition from the schema. language="java" /> + + +
- Sample configuration: Text objects +Sample configuration: Text objects This configuration for text objects defines the following: @@ -309,6 +325,8 @@ This configuration for text objects defines the following: - The vectorizer module (`text2vec-cohere`) and model (`embed-multilingual-v2.0`) - A set of properties (`title`, `body`) with `text` data types. + + ```json { "class": "Article", @@ -334,7 +352,7 @@ This configuration for text objects defines the following:
- Sample configuration: Nested objects +Sample configuration: Nested objects :::info Added in `v1.22` ::: @@ -342,7 +360,9 @@ This configuration for text objects defines the following: This configuration for nested objects defines the following: - The collection name (`Person`) + - The vectorizer module (`text2vec-huggingface`) + - A set of properties (`last_name`, `address`) - `last_name` has `text` data type @@ -350,6 +370,8 @@ This configuration for nested objects defines the following: - The `address` property has two nested properties (`street` and `city`) + + ```json { "class": "Person", @@ -374,9 +396,9 @@ This configuration for nested objects defines the following:
- Sample configuration: Generative search +Sample configuration: Generative search -This configuration for [retrieval augmented generation](../search/generative.md) defines the following: +This configuration for [retrieval augmented generation](https://www.google.com/search?q=../search/generative.md) defines the following: - The collection name (`Article`) - The default vectorizer module (`text2vec-openai`) @@ -385,6 +407,8 @@ This configuration for [retrieval augmented generation](../search/generative.md) - The tokenization option for the `url` property - The vectorization option (`skip` vectorization) for the `url` property + + ```json { "class": "Article", @@ -425,19 +449,21 @@ This configuration for [retrieval augmented generation](../search/generative.md)
- Sample configuration: Images +Sample configuration: Images This configuration for image search defines the following: - The collection name (`Image`) + - The vectorizer module (`img2vec-neural`) - The `image` property configures collection to store image data. - The vector index distance metric (`cosine`) + - A set of properties (`image`), with the `image` property set as `blob`. -For image searches, see [Image search](../search/image.md). +For image searches, see [Image search](https://www.google.com/search?q=../search/image.md). ```json { @@ -507,6 +533,14 @@ Fetch the database schema to retrieve all of the collection definitions. language="java" /> + + + ## Update a collection definition @@ -515,7 +549,7 @@ import RaftRFChangeWarning from "/_includes/1-25-replication-factor.mdx"; -You can update a collection definition to change the [mutable collection settings](../config-refs/collections.mdx#mutability). +You can update a collection definition to change the [mutable collection settings](https://www.google.com/search?q=../config-refs/collections.mdx%23mutability). @@ -558,6 +592,14 @@ You can update a collection definition to change the [mutable collection setting language="java" /> + + + ## Delete a collection @@ -569,9 +611,9 @@ import CautionSchemaDeleteClass from "/_includes/schema-delete-class.mdx"; ## Add a property
- - Indexing limitations after data import - + +Indexing limitations after data import + There are no index limitations when you add collection properties before you import data. @@ -588,16 +630,71 @@ We are working on a re-indexing API to allow you to re-index the data after addi
-import CodeSchemaAddProperties from "/_includes/code/schema.things.properties.add.mdx"; - - + + + + + + + + + + + + + + + + + + + + + + + ## Further resources -- [Manage collections: Vectorizer and vector index](./vector-config.mdx) -- [References: Collection definition](/weaviate/config-refs/collections.mdx) -- [Concepts: Data structure](../concepts/data.md) -- +- [Manage collections: Vectorizer and vector index](https://www.google.com/search?q=./vector-config.mdx) +- [References: Collection definition](https://www.google.com/search?q=/weaviate/config-refs/collections.mdx) +- [Concepts: Data structure](https://www.google.com/search?q=../concepts/data.md) +- API References: REST: Schema From 0f043fb051e2d953714ef030a14f734269aca31b Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Wed, 27 Aug 2025 10:02:48 +0200 Subject: [PATCH 07/18] Update docs --- _includes/code/csharp/ConnectionTests.cs | 3 + .../code/csharp/ManageCollectionsTests.cs | 196 +++++++++++++++++- 2 files changed, 189 insertions(+), 10 deletions(-) diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs index f192a82ea..fccfcf624 100644 --- a/_includes/code/csharp/ConnectionTests.cs +++ b/_includes/code/csharp/ConnectionTests.cs @@ -126,6 +126,9 @@ public async Task Should_Connect_Locally_With_Auth() { // START LocalAuth var localApiKey = Environment.GetEnvironmentVariable("WEAVIATE_LOCAL_API_KEY"); + // END LocalAuth + localApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + // START LocalAuth var client = Connect.Local( restPort: 8099, diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTests.cs index a8678e077..138bb39cc 100644 --- a/_includes/code/csharp/ManageCollectionsTests.cs +++ b/_includes/code/csharp/ManageCollectionsTests.cs @@ -4,13 +4,16 @@ using System; using System.Threading.Tasks; using System.Collections.Generic; +using static Weaviate.Client.Models.VectorIndex; -public class ManageDataTests : IAsyncLifetime +namespace WeaviateProject.Tests; + +public class ManageCollectionsTests : IAsyncLifetime { private readonly WeaviateClient weaviate; private readonly List _collectionNamesToDelete = new List(); - public ManageDataTests() + public ManageCollectionsTests() { weaviate = new WeaviateClient( new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 } @@ -109,7 +112,8 @@ public async Task CreateCollectionWithNamedVectors() Name = collectionName, VectorConfig = new VectorConfigList { - // TODO[g-despot]: How to specify source properties + // TODO[g-despot]: How to specify source properties, it's currently source properties + //Configure.Vectors.Text2VecCohere(sourceProperties: new[] { "title" }).New("title"), //Configure.Vectors.Text2VecOpenAI(sourceProperties: new[] { "title", "country" }).New("title_country"), Configure.Vectors.SelfProvided("default"), @@ -249,8 +253,10 @@ public async Task SetAndReadModules() { Name = collectionName, VectorConfig = Configure.Vectors.Text2VecOpenAI().New(), - //TODO[g-despot]: Missing model parameter for generative OpenAIConfig - GenerativeConfig = new Generative.OpenAIConfig() + GenerativeConfig = new Generative.OpenAIConfig + { + Model = "gpt-4o" + }, }; await weaviate.Collections.Create(articleGenerative); // END SetGenerative @@ -349,8 +355,8 @@ public async Task ConfigurePropertyModuleSettings() // START AddNamedVectors CollectionClient articles = weaviate.Collections.Use(collectionName); - // TODO[g-despot]: AddVector throws error - // await articles.Config.AddVector( + // TODO[g-despot]: AddVector throws error: vectorizer config of vector \"default\" is immutable + await articles.Config.AddVector(Configure.Vectors.Text2VecCohere().New("body_vector", properties: "body")); // TODO[g-despot]: Missing sourceProperties // Configure.Vectors.Text2VecCohere(sourceProperties: new[] { "body" }).New("body_vector") // Configure.Vectors.Text2VecCohere().New("body_vector") @@ -458,11 +464,11 @@ public async Task ConfigureMultiTenancyAndProperties() Collection config = await weaviate.Collections.Export(collectionName); Assert.True(config.MultiTenancyConfig.Enabled); - // START AddProp + // START AddProperty CollectionClient articles = weaviate.Collections.Use(collectionName); // TODO[g-despot]: AddProperty is internal // await articles.Config.AddProperty(Property.Text("body")); - // END AddProp + // END AddProperty config = await weaviate.Collections.Export(collectionName); // Assert.Contains(config.Properties, p => p.Name == "body"); @@ -510,7 +516,7 @@ await articles.Config.Update(c => c.Description = "An updated collection description."; // TODO[g-despot]: Updating property descriptions is missing c.InvertedIndexConfig.Bm25.K1 = 1.5f; - + VectorConfigUpdate vectorConfig = c.VectorConfig["default"]; vectorConfig.VectorIndexConfig.UpdateHNSW(vic => { @@ -548,6 +554,7 @@ public async Task ReadAndDeleteCollections() Assert.Equal(collectionName, articlesConfig.Name); // START ReadAllCollections + // TODO[g-despot]: Strange error: System.ArgumentException : Unsupported vectorizer type: text2colbert-jinaai (Parameter 'type') await foreach (Collection collection in weaviate.Collections.List()) { Console.WriteLine(collection.Name); @@ -561,4 +568,173 @@ public async Task ReadAndDeleteCollections() bool exists = await weaviate.Collections.Exists(collectionName); Assert.False(exists); } + + [Fact] + public async Task UpdateGenerativeModule() + { + string collectionName = AddTestCollection("Article"); + await weaviate.Collections.Delete(collectionName); + + // Arrange: Create a collection with the OpenAI generative module + Collection initialCollection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList { new VectorConfig("default", new Vectorizer.Text2VecOpenAI()) }, + GenerativeConfig = new Generative.OpenAIConfig() + }; + await weaviate.Collections.Create(initialCollection); + + CollectionClient collectionToUpdate = weaviate.Collections.Use(collectionName); + + // Act: Update the generative module to Cohere + // START UpdateGenerative + await collectionToUpdate.Config.Update(c => + { + c.GenerativeConfig = new Generative.OpenAIConfig(); // Update the generative module + }); + // END UpdateGenerative + + // Assert: Verify the change + Collection config = await weaviate.Collections.Export(collectionName); + Assert.Equal("generative-openai", (config.GenerativeConfig as Generative.Custom)?.Type); + } + + [Fact] + public async Task CreateCollectionWithMultiVectors() + { + string collectionName = AddTestCollection("DemoCollection"); + await weaviate.Collections.Delete(collectionName); + + // START MultiValueVectorCollection + Collection collection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList + { + // The factory function will automatically enable multi-vector support for the HNSW index + Configure.MultiVectors.Text2VecJinaAI().New("jina_colbert"), + // Must explicitly enable multi-vector support for the HNSW index + Configure.MultiVectors.SelfProvided("custom_multi_vector"), + }, + Properties = new List { Property.Text("text") }, + }; + await weaviate.Collections.Create(collection); + // END MultiValueVectorCollection + + // Assert + Collection config = await weaviate.Collections.Export(collectionName); + Assert.True(config.VectorConfig.ContainsKey("jina_colbert")); + Assert.True(config.VectorConfig.ContainsKey("custom_multi_vector")); + } + + // [Fact] + // public async Task CreateCollectionWithMultiVectorsAndMuvera() + // { + // string collectionName = AddTestCollection("DemoCollection"); + // await weaviate.Collections.Delete(collectionName); + + // // START MultiValueVectorMuvera + // Collection collection = new Collection + // { + // Name = collectionName, + // VectorConfig = new VectorConfigList + // { + // Configure.MultiVectors.Text2VecJinaAI( + // "jina_colbert", + // indexConfig: new VectorIndex.HNSW + // { + // MultiVector = new VectorIndexConfig.MultiVectorConfig + // { + // Encoding = new VectorIndexConfig.MuveraEncoding() { }, + // }, + // } + // ), + // Configure.MultiVectors.SelfProvided( + // "custom_multi_vector", + // indexConfig: new VectorIndex.HNSW + // { + // MultiVector = new VectorIndexConfig.MultiVectorConfig + // { + // Encoding = new VectorIndexConfig.MuveraEncoding() + // } + // } + // ), + // } + // }; + // await weaviate.Collections.Create(collection); + // // END MultiValueVectorMuvera + + // // Assert + // Collection config = await weaviate.Collections.Export(collectionName); + // VectorIndex.HNSW jinaConfig = Assert.IsType(config.VectorConfig["jina_colbert"].VectorIndexConfig); + // Assert.IsType(jinaConfig.MultiVector?.Encoding); + // } + + [Fact] + public async Task CreateCollectionWithMultiVectorsAndPQ() + { + string collectionName = AddTestCollection("DemoCollection"); + await weaviate.Collections.Delete(collectionName); + + // START MultiValueVectorPQ + Collection collection = new Collection + { + Name = collectionName, + VectorConfig = new VectorConfigList + { + // Configure.MultiVectors.Text2VecJinaAI( + // "jina_colbert", + // //sourceProperties: new[] { "text" }, + // // TODO[g-despot]: Why is vectorIndexConfig missing from Text2VecJinaAI? + // vectorIndexConfig: new VectorIndex.HNSW + // { + // Quantizer = new Quantizers.BQ() { Cache = true, RescoreLimit = 64 }, + // } + // ), + Configure.MultiVectors.SelfProvided( + "custom_multi_vector", + indexConfig: new VectorIndex.HNSW + { + Quantizer = new Quantizers.BQ() { Cache = true, RescoreLimit = 64 }, + } + ), + } + }; + await weaviate.Collections.Create(collection); + // END MultiValueVectorPQ + + // Assert + Collection config = await weaviate.Collections.Export(collectionName); + // VectorIndex.HNSW jinaConfig = Assert.IsType(config.VectorConfig["jina_colbert"].VectorIndexConfig); + // VectorIndex.Quantizers.PQ quantizer = Assert.IsType(jinaConfig.Quantizer); + // Assert.Equal(100000, quantizer.TrainingLimit); + } + + [Fact] + public async Task ConfigureAllReplicationSettings() + { + // Connect to the Weaviate instance configured for replication tests on port 8180 + WeaviateClient replicationClient = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8180 }); + string collectionName = AddTestCollection("Article"); + await replicationClient.Collections.Delete(collectionName); + + // START AllReplicationSettings + Collection collection = new Collection + { + Name = collectionName, + ReplicationConfig = new ReplicationConfig + { + Factor = 3, + AsyncEnabled = true, + DeletionStrategy = DeletionStrategy.TimeBasedResolution, + }, + }; + await replicationClient.Collections.Create(collection); + // END AllReplicationSettings + + // Assert + Collection config = await replicationClient.Collections.Export(collectionName); + Assert.True(config.ReplicationConfig.AsyncEnabled); + Assert.Equal(DeletionStrategy.TimeBasedResolution, config.ReplicationConfig.DeletionStrategy); + } } \ No newline at end of file From acb262879e51d031d2265c899d25585eecb4c481 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:26:20 +0200 Subject: [PATCH 08/18] Add code examples --- _includes/code/csharp/BatchImportTests.cs | 572 ++++++++++++++++++++++ _includes/code/csharp/ManageDataTests.cs | 335 +++++++++++++ 2 files changed, 907 insertions(+) create mode 100644 _includes/code/csharp/BatchImportTests.cs create mode 100644 _includes/code/csharp/ManageDataTests.cs diff --git a/_includes/code/csharp/BatchImportTests.cs b/_includes/code/csharp/BatchImportTests.cs new file mode 100644 index 000000000..3b90b7f4e --- /dev/null +++ b/_includes/code/csharp/BatchImportTests.cs @@ -0,0 +1,572 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text.Json; +using System.Security.Cryptography; +using System.Text; +using System.Net.Http; + +namespace WeaviateProject.Tests; + +public class BatchImportTests : IAsyncLifetime +{ + private readonly WeaviateClient weaviate; + private readonly List _collectionNamesToDelete = new List(); + private const int MAX_ROWS_TO_IMPORT = 50; // limit vectorization calls + + public BatchImportTests() + { + weaviate = new WeaviateClient( + new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 } + ); + } + + public async Task InitializeAsync() + { + // Clean slate + await weaviate.Collections.Delete("MyCollection"); + + // Create collection with self-provided vectors + await weaviate.Collections.Create(new Collection + { + Name = "MyCollection", + VectorConfig = new VectorConfig("default", new Vectorizer.SelfProvided()) + }); + } + + public async Task DisposeAsync() + { + foreach (string name in _collectionNamesToDelete) + { + await weaviate.Collections.Delete(name); + } + await weaviate.Collections.Delete("MyCollection"); + await weaviate.Collections.Delete("JeopardyQuestion"); + } + + [Fact] + public async Task BasicBatchImport() + { + // START BasicBatchImportExample + var dataRows = Enumerable.Range(0, 5).Select(i => new { title = $"Object {i + 1}" }).ToList(); + + var collection = weaviate.Collections.Use("MyCollection"); + + // highlight-start + var result = await collection.Data.InsertMany(add => + { + foreach (var dataRow in dataRows) + { + add(dataRow); + } + }); + // highlight-end + + var failedObjects = result.Where(r => r.Error != null).ToList(); + if (failedObjects.Any()) + { + Console.WriteLine($"Number of failed imports: {failedObjects.Count}"); + Console.WriteLine($"First failed object: {failedObjects[0].Error}"); + } + // END BasicBatchImportExample + + // Test + Assert.Equal(5, result.Count(r => r.Error == null)); + } + + [Fact] + public async Task InsertManyWithID() + { + // InsertManyWithIDExample + // highlight-start + // For deterministic UUID generation + // highlight-end + + var data = new[] + { + new + { + properties = new { title = "Object 1" }, + // highlight-start + id = GenerateUuid5(new { title = "Object 1" }) + // highlight-end + }, + new + { + properties = new { title = "Object 2" }, + id = GenerateUuid5(new { title = "Object 2" }) + }, + new + { + properties = new { title = "Object 3" }, + id = GenerateUuid5(new { title = "Object 3" }) + } + }; + + var collection = weaviate.Collections.Use("MyCollection"); // Replace with your collection name + var result = await collection.Data.InsertMany(add => + { + foreach (var item in data) + { + add(item.properties, item.id); + } + }); + // END InsertManyWithIDExample + + // Tests + Assert.Equal(3, result.Count(r => r.Error == null)); + var firstId = GenerateUuid5(new { title = "Object 1" }); + var response = await collection.Query.FetchObjectByID(firstId); + Assert.NotNull(response); + } + + [Fact] + public async Task InsertManyWithVector() + { + // InsertManyWithVectorExample + var data = new[] + { + new + { + properties = new { title = "Object 1" }, + // highlight-start + vector = Enumerable.Repeat(0.1f, 6).ToArray() + // highlight-end + }, + new + { + properties = new { title = "Object 2" }, + vector = Enumerable.Repeat(0.2f, 6).ToArray() + }, + new + { + properties = new { title = "Object 3" }, + vector = Enumerable.Repeat(0.3f, 6).ToArray() + } + }; + + var collection = weaviate.Collections.Use("MyCollection"); // Replace with your collection name + var result = await collection.Data.InsertMany(add => + { + foreach (var item in data) + { + add(item.properties, Guid.NewGuid(), item.vector); + } + }); + // END InsertManyWithVectorExample + + // Tests + Assert.Equal(3, result.Count(r => r.Error == null)); + } + + [Fact] + public async Task BatchImportWithID() + { + // START BatchImportWithIDExample + // highlight-start + // For deterministic UUID generation + // highlight-end + + var dataRows = Enumerable.Range(0, 5).Select(i => new { title = $"Object {i + 1}" }).ToList(); + + var collection = weaviate.Collections.Use("MyCollection"); + + // highlight-start + var result = await collection.Data.InsertMany(add => + { + foreach (var dataRow in dataRows) + { + var objUuid = GenerateUuid5(dataRow); + add(dataRow, objUuid); + } + }); + // highlight-end + + var failedObjects = result.Where(r => r.Error != null).ToList(); + if (failedObjects.Any()) + { + Console.WriteLine($"Number of failed imports: {failedObjects.Count}"); + Console.WriteLine($"First failed object: {failedObjects[0].Error}"); + } + // END BatchImportWithIDExample + + // Test + Assert.Equal(5, result.Count(r => r.Error == null)); + var lastUuid = GenerateUuid5(new { title = "Object 5" }); + var respObj = await collection.Query.FetchObjectByID(lastUuid); + Assert.NotNull(respObj); + } + + [Fact] + public async Task BatchImportWithVector() + { + // START BatchImportWithVectorExample + var dataRows = Enumerable.Range(0, 5).Select(i => new { title = $"Object {i + 1}" }).ToList(); + var vectors = Enumerable.Range(0, 5).Select(_ => Enumerable.Repeat(0.1f, 1536).ToArray()).ToList(); + + var collection = weaviate.Collections.Use("MyCollection"); + + // highlight-start + var result = await collection.Data.InsertMany(add => + { + for (int i = 0; i < dataRows.Count; i++) + { + add(dataRows[i], Guid.NewGuid(), vectors[i]); + } + }); + // highlight-end + + var failedObjects = result.Where(r => r.Error != null).ToList(); + if (failedObjects.Any()) + { + Console.WriteLine($"Number of failed imports: {failedObjects.Count}"); + Console.WriteLine($"First failed object: {failedObjects[0].Error}"); + } + // END BatchImportWithVectorExample + + // Test + Assert.Equal(5, result.Count(r => r.Error == null)); + } + + [Fact] + public async Task BatchImportWithNamedVectors() + { + // Setup collection with named vectors + await weaviate.Collections.Delete("MyCollection"); + await weaviate.Collections.Create(new Collection + { + Name = "MyCollection", + Properties = new List + { + Property.Text("title"), + Property.Text("body") + }, + VectorConfig = new[] + { + new VectorConfig("title", new Vectorizer.Text2VecOpenAI()), + new VectorConfig("body", new Vectorizer.Text2VecOpenAI()) + } + }); + + // START BatchImportWithNamedVectors + var dataRows = Enumerable.Range(0, 5).Select(i => new + { + title = $"Object {i + 1}", + body = $"Body {i + 1}" + }).ToList(); + + var titleVectors = Enumerable.Range(0, 5).Select(_ => Enumerable.Repeat(0.12f, 1536).ToArray()).ToList(); + var bodyVectors = Enumerable.Range(0, 5).Select(_ => Enumerable.Repeat(0.34f, 1536).ToArray()).ToList(); + + var collection = weaviate.Collections.Use("MyCollection"); + + // highlight-start + var result = await collection.Data.InsertMany(add => + { + for (int i = 0; i < dataRows.Count; i++) + { + add( + dataRows[i], + Guid.NewGuid(), + new Dictionary + { + ["title"] = titleVectors[i], + ["body"] = bodyVectors[i] + } + ); + } + }); + // highlight-end + + var failedObjects = result.Where(r => r.Error != null).ToList(); + if (failedObjects.Any()) + { + Console.WriteLine($"Number of failed imports: {failedObjects.Count}"); + Console.WriteLine($"First failed object: {failedObjects[0].Error}"); + } + // END BatchImportWithNamedVectors + + // Test + var response = await collection.Query.List(); + Assert.Equal(5, response.Objects.Count()); + foreach (var obj in response.Objects) + { + Assert.Contains("Object", (string)obj.Properties["title"]); + Assert.Contains("Body", (string)obj.Properties["body"]); + } + } + + [Fact] + public async Task BatchImportWithReference() + { + // Setup collections + await weaviate.Collections.Delete("Author"); + await weaviate.Collections.Delete("Publication"); + + await weaviate.Collections.Create(new Collection + { + Name = "Publication", + Properties = new List { Property.Text("title") } + }); + + await weaviate.Collections.Create(new Collection + { + Name = "Author", + Properties = new List { Property.Text("name") }, + // TODO[g-despot]: Why is description required? + References = new List + { + new ReferenceProperty { Name = "writesFor", TargetCollection = "Publication", Description = "The publication this author writes for." } + } + }); + + var authors = weaviate.Collections.Use("Author"); + var publications = weaviate.Collections.Use("Publication"); + + var fromUuid = await authors.Data.Insert(new { name = "Jane Austen" }); + await publications.Data.Insert(new { title = "Ye Olde Times" }); + + var pubResult = await publications.Query.List(limit: 1); + var targetUuid = pubResult.Objects.First().ID; + + // BatchImportWithRefExample + var collection = weaviate.Collections.Use("Author"); + + var referenceResult = await collection.Data.ReferenceAddMany( + new DataReference(fromUuid, "writesFor", (Guid)targetUuid) + ); + + if (referenceResult.HasErrors) + { + var failedReferences = referenceResult.Errors; + Console.WriteLine($"Number of failed imports: {failedReferences.Count}"); + Console.WriteLine($"First failed reference: {failedReferences[0]}"); + } + // END BatchImportWithRefExample + + // Test + var response = await collection.Query.FetchObjectByID( + fromUuid, + // TODO[g-despot]: Should this also accept a single QueryReference object? + references: [new QueryReference(linkOn: "writesFor", fields: new[] { "title" })] + ); + + Assert.Equal("Ye Olde Times", response.References["writesFor"][0].Properties["title"]); + } + + [Fact] + public async Task StreamDataJSON() + { + // Setup + await weaviate.Collections.Delete("JeopardyQuestion"); + await weaviate.Collections.Create(new Collection { Name = "JeopardyQuestion" }); + + // Download the data + using var httpClient = new HttpClient(); + var jsonData = await httpClient.GetStringAsync("https://raw.githubusercontent.com/weaviate-tutorials/edu-datasets/main/jeopardy_1k.json"); + await File.WriteAllTextAsync("jeopardy_1k.json", jsonData); + + // START JSON streaming + var counter = 0; + var interval = 200; // print progress every this many records + + Console.WriteLine("JSON streaming, to avoid running out of memory on large files..."); + + var collection = weaviate.Collections.Use("JeopardyQuestion"); + var objects = JsonSerializer.Deserialize>>(jsonData); + + var batchSize = 100; + for (int i = 0; i < objects.Count; i += batchSize) + { + var batch = objects.Skip(i).Take(batchSize).ToList(); + + await collection.Data.InsertMany(add => + { + foreach (var obj in batch) + { + var properties = new + { + question = obj["Question"], + answer = obj["Answer"] + }; + add(properties); + // If you Bring Your Own Vectors, add the vector parameter here + // add(properties, Guid.NewGuid(), vectorArray); + } + }); + + // Calculate and display progress + counter += batch.Count; + if (counter % interval == 0) + { + Console.WriteLine($"Imported {counter} articles..."); + } + } + + Console.WriteLine($"Finished importing {counter} articles."); + // END JSON streaming + + // Test - Note: Count() method may not exist, using FetchObjects instead + var questions = weaviate.Collections.Use("JeopardyQuestion"); + var testBatch = await questions.Query.List(limit: 10); + Assert.True(testBatch.Objects.Any()); + + // Cleanup + File.Delete("jeopardy_1k.json"); + } + + [Fact] + public async Task StreamDataCSV() + { + // Setup - create CSV from JSON + using var httpClient = new HttpClient(); + var jsonData = await httpClient.GetStringAsync("https://raw.githubusercontent.com/weaviate-tutorials/edu-datasets/main/jeopardy_1k.json"); + var objects = JsonSerializer.Deserialize>>(jsonData); + + // Convert to CSV + var csvLines = new List { "Question,Answer,Category" }; + foreach (var obj in objects) + { + // Use .ToString() to safely access the values + var question = obj.ContainsKey("Question") ? obj["Question"]?.ToString()?.Replace(",", "\\,") : ""; + var answer = obj.ContainsKey("Answer") ? obj["Answer"]?.ToString()?.Replace(",", "\\,") : ""; + var category = obj.ContainsKey("Category") ? obj["Category"]?.ToString()?.Replace(",", "\\,") : ""; + csvLines.Add($"{question},{answer},{category}"); + } + await File.WriteAllLinesAsync("jeopardy_1k.csv", csvLines); + + await weaviate.Collections.Delete("JeopardyQuestion"); + await weaviate.Collections.Create(new Collection { Name = "JeopardyQuestion" }); + + // START CSV streaming + var counter = 0; + var interval = 200; // print progress every this many records + + Console.WriteLine("CSV streaming with chunking, to not load all records in RAM at once..."); + + var collection = weaviate.Collections.Use("JeopardyQuestion"); + var csvContent = await File.ReadAllLinesAsync("jeopardy_1k.csv"); + var headers = csvContent[0].Split(','); + + var chunkSize = 100; // number of rows per chunk + for (int i = 1; i < csvContent.Length; i += chunkSize) + { + var chunk = csvContent.Skip(i).Take(chunkSize).ToList(); + + await collection.Data.InsertMany(add => + { + foreach (var line in chunk) + { + var values = line.Split(','); + var properties = new + { + question = values[0].Replace("\\,", ","), + answer = values[1].Replace("\\,", ",") + }; + add(properties); + // If you Bring Your Own Vectors, add the vector parameter here + // add(properties, Guid.NewGuid(), vectorArray); + } + }); + + // Calculate and display progress + counter += chunk.Count; + if (counter % interval == 0) + { + Console.WriteLine($"Imported {counter} articles..."); + } + } + + Console.WriteLine($"Finished importing {counter} articles."); + // END CSV streaming + + // Test + var questions = weaviate.Collections.Use("JeopardyQuestion"); + var testBatch = await questions.Query.List(limit: 10); + Assert.True(testBatch.Objects.Any()); + + // Cleanup + File.Delete("jeopardy_1k.csv"); + } + + [Fact] + public async Task BatchVectorClient() + { + await weaviate.Collections.Delete("NewCollection"); + + // START BatchVectorClient + var collection = await weaviate.Collections.Create(new Collection + { + Name = "NewCollection", + Properties = new List + { + Property.Text("url"), + Property.Text("title"), + Property.Text("raw"), + Property.Text("sha") + }, + VectorConfig = new[] + { + new VectorConfig("cohereFirst", new Vectorizer.Text2VecCohere()), + new VectorConfig("cohereSecond", new Vectorizer.Text2VecCohere()) + } + }); + // END BatchVectorClient + + Assert.NotNull(collection); + await weaviate.Collections.Delete("NewCollection"); + } + + [Fact] + public async Task BatchVectorizationClientModify() + { + var rpmEmbeddings = 100; + var tpmEmbeddings = 10000; + + var cohereKey = Environment.GetEnvironmentVariable("COHERE_API_KEY") ?? ""; + var openaiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? ""; + + // START BatchVectorizationClientModify + // Note: The C# client may not have direct equivalent of Python's Integrations configuration + // This is a placeholder showing the concept + + // Each model provider may expose different parameters + // In the C# client, these might be configured differently + var clientConfig = new ClientConfiguration + { + RestAddress = "localhost", + RestPort = 8080, + }; + + // Rate limiting parameters would typically be configured at the collection level + // or through the vectorizer configuration in C# + // END BatchVectorizationClientModify + + // Note: The actual implementation would depend on how the C# client handles integrations + Assert.NotNull(clientConfig); + } + + // Helper method for UUID v5 generation + private static Guid GenerateUuid5(object data) + { + var json = JsonSerializer.Serialize(data); + var bytes = Encoding.UTF8.GetBytes(json); + + using (var sha1 = SHA1.Create()) + { + var hash = sha1.ComputeHash(bytes); + var guidBytes = new byte[16]; + Array.Copy(hash, guidBytes, 16); + + guidBytes[6] = (byte)((guidBytes[6] & 0x0F) | 0x50); + guidBytes[8] = (byte)((guidBytes[8] & 0x3F) | 0x80); + + return new Guid(guidBytes); + } + } +} \ No newline at end of file diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageDataTests.cs new file mode 100644 index 000000000..6b0844761 --- /dev/null +++ b/_includes/code/csharp/ManageDataTests.cs @@ -0,0 +1,335 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; + +namespace WeaviateProject.Tests; + +public class ManageDataTests : IAsyncLifetime +{ + private readonly WeaviateClient weaviate; + private readonly List _collectionNamesToDelete = new List(); + + public ManageDataTests() + { + weaviate = new WeaviateClient( + new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 } + ); + } + + private string AddTestCollection(string name) + { + _collectionNamesToDelete.Add(name); + return name; + } + + public async Task InitializeAsync() + { + // Clean slate - delete collections if they exist + await weaviate.Collections.Delete("JeopardyQuestion"); + await weaviate.Collections.Delete("WineReviewNV"); + await weaviate.Collections.Delete("Publication"); + await weaviate.Collections.Delete("Author"); + + // Create JeopardyQuestion collection + await weaviate.Collections.Create(new Collection + { + Name = "JeopardyQuestion", + VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecOpenAI()) + }); + + // Create WineReviewNV collection with named vectors + await weaviate.Collections.Create(new Collection + { + Name = "WineReviewNV", + Properties = new List + { + Property.Text("review_body", "Review body"), + Property.Text("title", "Name of the wine"), + Property.Text("country", "Originating country") + }, + VectorConfig = new[] + { + // TODO[g-despot]: Uncomment when source properties available + // new VectorConfig("title", new Vectorizer.Text2VecOpenAI()) { SourceProperties = new[] { "title" } }, + // new VectorConfig("review_body", new Vectorizer.Text2VecOpenAI()) { SourceProperties = new[] { "review_body" } }, + // new VectorConfig("title_country", new Vectorizer.Text2VecOpenAI()) { SourceProperties = new[] { "title", "country" } } + new VectorConfig("title", new Vectorizer.Text2VecOpenAI()), + new VectorConfig("review_body", new Vectorizer.Text2VecOpenAI()), + new VectorConfig("title_country", new Vectorizer.Text2VecOpenAI()) + } + }); + + // Create Publication collection for geo tests + await weaviate.Collections.Create(new Collection + { + Name = "Publication", + Properties = new List + { + Property.GeoCoordinate("headquartersGeoLocation") + } + }); + + // Create Author collection for existence checks + await weaviate.Collections.Create(new Collection + { + Name = "Author", + Properties = new List + { + Property.Text("name") + }, + VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecOpenAI()) + }); + } + + public async Task DisposeAsync() + { + foreach (string name in _collectionNamesToDelete) + { + await weaviate.Collections.Delete(name); + } + await weaviate.Collections.Delete("JeopardyQuestion"); + await weaviate.Collections.Delete("WineReviewNV"); + await weaviate.Collections.Delete("Publication"); + await weaviate.Collections.Delete("Author"); + } + + [Fact] + public async Task CreateObject() + { + // CreateObject START + var jeopardy = weaviate.Collections.Use("JeopardyQuestion"); + + // highlight-start + var uuid = await jeopardy.Data.Insert(new + { + // highlight-end + question = "This vector DB is OSS & supports automatic property type inference on import", + // answer = "Weaviate", // properties can be omitted + newProperty = 123 // will be automatically added as a number property + }); + + Console.WriteLine(uuid); // the return value is the object's UUID + // CreateObject END + + // Test + var result = await jeopardy.Query.FetchObjectByID(uuid); + var newPropertyValue = Convert.ToInt64(result?.Properties["newProperty"]); + Assert.Equal(123L, newPropertyValue); + } + + [Fact] + public async Task CreateObjectWithVector() + { + // CreateObjectWithVector START + var jeopardy = weaviate.Collections.Use("JeopardyQuestion"); + var uuid = await jeopardy.Data.Insert( + new + { + question = "This vector DB is OSS and supports automatic property type inference on import", + answer = "Weaviate" + }, + // highlight-start + vectors: Enumerable.Repeat(0.12345f, 1536).ToArray() + // highlight-end + ); + + Console.WriteLine(uuid); // the return value is the object's UUID + // CreateObjectWithVector END + + Assert.NotEqual(Guid.Empty, uuid); + } + + [Fact] + public async Task CreateObjectNamedVectors() + { + // CreateObjectNamedVectors START + var reviews = weaviate.Collections.Use("WineReviewNV"); // This collection must have named vectors configured + var uuid = await reviews.Data.Insert( + new + { + title = "A delicious Riesling", + review_body = "This wine is a delicious Riesling which pairs well with seafood.", + country = "Germany" + }, + // highlight-start + // Specify the named vectors, following the collection definition + vectors: new Dictionary + { + ["title"] = Enumerable.Repeat(0.12345f, 1536).ToArray(), + ["review_body"] = Enumerable.Repeat(0.31313f, 1536).ToArray(), + ["title_country"] = Enumerable.Repeat(0.05050f, 1536).ToArray() + } + // highlight-end + ); + + Console.WriteLine(uuid); // the return value is the object's UUID + // CreateObjectNamedVectors END + + // Test + var result = await reviews.Query.FetchObjectByID(uuid, metadata: MetadataOptions.Vector); + Assert.NotNull(result?.Vectors); + Assert.Equal(3, result.Vectors.Count); + Assert.True(result.Vectors.ContainsKey("title")); + Assert.True(result.Vectors.ContainsKey("review_body")); + Assert.True(result.Vectors.ContainsKey("title_country")); + } + + [Fact] + public async Task CreateObjectWithDeterministicId() + { + // CreateObjectWithDeterministicId START + // highlight-start + // For deterministic UUID generation + // highlight-end + + var dataObject = new + { + question = "This vector DB is OSS and supports automatic property type inference on import", + answer = "Weaviate" + }; + + var jeopardy = weaviate.Collections.Use("JeopardyQuestion"); + var uuid = await jeopardy.Data.Insert( + dataObject, + // highlight-start + id: GenerateUuid5(dataObject) + // highlight-end + ); + // CreateObjectWithDeterministicId END + + // Test + Assert.Equal(GenerateUuid5(dataObject), uuid); + await jeopardy.Data.Delete(uuid); // Clean up + } + + [Fact] + public async Task CreateObjectWithId() + { + // CreateObjectWithId START + var properties = new + { + question = "This vector DB is OSS and supports automatic property type inference on import", + answer = "Weaviate" + }; + var jeopardy = weaviate.Collections.Use("JeopardyQuestion"); + var uuid = await jeopardy.Data.Insert( + properties, + // highlight-start + id: Guid.Parse("12345678-e64f-5d94-90db-c8cfa3fc1234") + // highlight-end + ); + + Console.WriteLine(uuid); // the return value is the object's UUID + // CreateObjectWithId END + + // Test + var result = await jeopardy.Query.FetchObjectByID(uuid); + Assert.Equal(properties.question, result?.Properties["question"]); + } + + [Fact] + public async Task WithGeoCoordinates() + { + // START WithGeoCoordinates + var publications = weaviate.Collections.Use("Publication"); + + await publications.Data.Insert( + new + { + headquartersGeoLocation = new GeoCoordinate( + 52.3932696f, + 4.8374263f + ) + } + ); + // END WithGeoCoordinates + + // TEST - Confirm insert & delete object + // var response = await publications.Query.List( + // where: Filter.Property("headquartersGeoLocation") + // .WithinGeoRange( + // new GeoCoordinate(52.39f, 4.84f), + // 1000 // In meters + // ) + // ); + + // Assert.Single(response.Objects); + // var objUuid = response.Objects.First().ID; + // await publications.Data.Delete(objUuid); + } + + [Fact] + public async Task CheckForAnObject() + { + // START CheckForAnObject + // generate uuid based on the key properties used during data insert + var objectUuid = GenerateUuid5(new { name = "Author to fetch" }); + + // END CheckForAnObject + + var authorsCollection = weaviate.Collections.Use("Author"); + await authorsCollection.Data.Insert( + new { name = "Author to fetch" }, + objectUuid, // Custom UUID for testing + Enumerable.Repeat(0.3f, 1536).ToArray() // If you want to specify a vector + ); + + // START CheckForAnObject + var authors = weaviate.Collections.Use("Author"); + // highlight-start + var author = await authors.Query.FetchObjectByID(objectUuid); + var authorExists = author != null; + // highlight-end + + Console.WriteLine("Author exists: " + authorExists); + // END CheckForAnObject + + Assert.True(authorExists); + await authorsCollection.Data.Delete(objectUuid); + var deletedAuthor = await authorsCollection.Query.FetchObjectByID(objectUuid); + Assert.Null(deletedAuthor); + } + + [Fact] + public async Task ValidateObject() + { + // ValidateObject START + // Validate is currently not supported with the Weaviate C# client + // ValidateObject END + + // Note: Validation functionality is not yet implemented in the C# client + // This test serves as a placeholder for when the feature becomes available + + Assert.True(true, "Validation not yet supported - placeholder test"); + } + + // Helper method for UUID v5 generation + private static Guid GenerateUuid5(object data) + { + // Serialize the object to JSON for consistent hashing + var json = JsonSerializer.Serialize(data); + var bytes = Encoding.UTF8.GetBytes(json); + + using (var sha1 = SHA1.Create()) + { + var hash = sha1.ComputeHash(bytes); + + // Convert first 16 bytes to GUID + var guidBytes = new byte[16]; + Array.Copy(hash, guidBytes, 16); + + // Set version (5) and variant bits according to UUID v5 spec + guidBytes[6] = (byte)((guidBytes[6] & 0x0F) | 0x50); + guidBytes[8] = (byte)((guidBytes[8] & 0x3F) | 0x80); + + return new Guid(guidBytes); + } + } +} \ No newline at end of file From 8f488248894dad84ce45328d5da5b25649aa97c2 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:31:25 +0200 Subject: [PATCH 09/18] Update code --- _includes/code/csharp/ManageDataTests.cs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageDataTests.cs index 6b0844761..71838692d 100644 --- a/_includes/code/csharp/ManageDataTests.cs +++ b/_includes/code/csharp/ManageDataTests.cs @@ -251,18 +251,16 @@ await publications.Data.Insert( ); // END WithGeoCoordinates - // TEST - Confirm insert & delete object - // var response = await publications.Query.List( - // where: Filter.Property("headquartersGeoLocation") - // .WithinGeoRange( - // new GeoCoordinate(52.39f, 4.84f), - // 1000 // In meters - // ) - // ); - - // Assert.Single(response.Objects); - // var objUuid = response.Objects.First().ID; - // await publications.Data.Delete(objUuid); + var response = await publications.Query.List( + filter: Filter.Property("headquartersGeoLocation") + .WithinGeoRange( + new GeoCoordinateConstraint(52.39f, 4.84f, 1000) + ) + ); + + Assert.Single(response.Objects); + var objUuid = response.Objects.First().ID; + await publications.Data.Delete((Guid)objUuid); } [Fact] From 54bce65ff131a381390fc95525306172cea0ecad Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 23 Sep 2025 09:07:02 +0200 Subject: [PATCH 10/18] Update code --- _includes/code/csharp/BatchImportTests.cs | 15 +- _includes/code/csharp/CollectionTests.cs | 110 -------- _includes/code/csharp/ConnectionTests.cs | 4 +- .../code/csharp/ManageCollectionsTests.cs | 4 +- _includes/code/csharp/ManageDataTests.cs | 10 +- _includes/code/csharp/ObjectTests.cs | 52 ---- _includes/code/csharp/SearchBasicsTests.cs | 260 ++++++++++++++++++ _includes/code/csharp/SearchTests.cs | 56 ---- .../code/csharp/WeaviateProject.Tests.csproj | 3 +- 9 files changed, 277 insertions(+), 237 deletions(-) delete mode 100644 _includes/code/csharp/CollectionTests.cs delete mode 100644 _includes/code/csharp/ObjectTests.cs create mode 100644 _includes/code/csharp/SearchBasicsTests.cs delete mode 100644 _includes/code/csharp/SearchTests.cs diff --git a/_includes/code/csharp/BatchImportTests.cs b/_includes/code/csharp/BatchImportTests.cs index 3b90b7f4e..a521932a3 100644 --- a/_includes/code/csharp/BatchImportTests.cs +++ b/_includes/code/csharp/BatchImportTests.cs @@ -292,7 +292,7 @@ await weaviate.Collections.Create(new Collection // END BatchImportWithNamedVectors // Test - var response = await collection.Query.List(); + var response = await collection.Query.FetchObjects(); Assert.Equal(5, response.Objects.Count()); foreach (var obj in response.Objects) { @@ -319,10 +319,7 @@ await weaviate.Collections.Create(new Collection Name = "Author", Properties = new List { Property.Text("name") }, // TODO[g-despot]: Why is description required? - References = new List - { - new ReferenceProperty { Name = "writesFor", TargetCollection = "Publication", Description = "The publication this author writes for." } - } + References = [new Reference("writesFor", "Publication", "The publication this author writes for.")] }); var authors = weaviate.Collections.Use("Author"); @@ -331,7 +328,7 @@ await weaviate.Collections.Create(new Collection var fromUuid = await authors.Data.Insert(new { name = "Jane Austen" }); await publications.Data.Insert(new { title = "Ye Olde Times" }); - var pubResult = await publications.Query.List(limit: 1); + var pubResult = await publications.Query.FetchObjects(limit: 1); var targetUuid = pubResult.Objects.First().ID; // BatchImportWithRefExample @@ -353,7 +350,7 @@ await weaviate.Collections.Create(new Collection var response = await collection.Query.FetchObjectByID( fromUuid, // TODO[g-despot]: Should this also accept a single QueryReference object? - references: [new QueryReference(linkOn: "writesFor", fields: new[] { "title" })] + returnReferences: [new QueryReference(linkOn: "writesFor", fields: new[] { "title" })] ); Assert.Equal("Ye Olde Times", response.References["writesFor"][0].Properties["title"]); @@ -413,7 +410,7 @@ await collection.Data.InsertMany(add => // Test - Note: Count() method may not exist, using FetchObjects instead var questions = weaviate.Collections.Use("JeopardyQuestion"); - var testBatch = await questions.Query.List(limit: 10); + var testBatch = await questions.Query.FetchObjects(limit: 10); Assert.True(testBatch.Objects.Any()); // Cleanup @@ -487,7 +484,7 @@ await collection.Data.InsertMany(add => // Test var questions = weaviate.Collections.Use("JeopardyQuestion"); - var testBatch = await questions.Query.List(limit: 10); + var testBatch = await questions.Query.FetchObjects(limit: 10); Assert.True(testBatch.Objects.Any()); // Cleanup diff --git a/_includes/code/csharp/CollectionTests.cs b/_includes/code/csharp/CollectionTests.cs deleted file mode 100644 index f028e6481..000000000 --- a/_includes/code/csharp/CollectionTests.cs +++ /dev/null @@ -1,110 +0,0 @@ -using Xunit; -using Weaviate.Client; -using System; -using System.Threading.Tasks; -using Weaviate.Client.Models; - -namespace WeaviateProject.Tests; - -public class CollectionTest -{ - // [Fact] - public async Task Should_Create_Collection() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - // START BasicCreateCollection - var collectionName = "Article"; - // END BasicCreateCollection - // Clean up previous runs by deleting the collection if it exists - if (await client.Collections.Exists(collectionName)) - { - await client.Collections.Delete(collectionName); - Console.WriteLine($"Deleted existing collection: '{collectionName}'"); - } - - // START BasicCreateCollection - var articleCollection = new Collection - { - Name = collectionName, - Description = "Collection description", - }; - - var collection = await client.Collections.Create(articleCollection); - // END BasicCreateCollection - Console.WriteLine($"Successfully created collection: '{collectionName}'"); - } - - // [Fact] - public async Task Should_Create_Collection_With_Properties() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - // START CreateCollectionWithProperties - var collectionName = "Article"; - // END CreateCollectionWithProperties - // Clean up previous runs by deleting the collection if it exists - if (await client.Collections.Exists(collectionName)) - { - await client.Collections.Delete(collectionName); - Console.WriteLine($"Deleted existing collection: '{collectionName}'"); - } - - // START CreateCollectionWithProperties - var articleCollection = new Collection - { - Name = collectionName, - Description = "something", - Properties = [Property.Int("number_property"), Property.Text("test_property")], - // Properties = [.. Property.FromCollection()], // For dynamic properties, you can use the FromCollection method - }; - - var collection = await client.Collections.Create(articleCollection); - // END CreateCollectionWithProperties - Console.WriteLine($"Successfully created collection: '{collectionName}'"); - } - - // [Fact] - public async Task Should_Create_Collection_With_Vectorizer() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - // START CreateCollectionWithVectorizer - var collectionName = "Article"; - // END CreateCollectionWithVectorizer - // Clean up previous runs by deleting the collection if it exists - if (await client.Collections.Exists(collectionName)) - { - await client.Collections.Delete(collectionName); - Console.WriteLine($"Deleted existing collection: '{collectionName}'"); - } - - // START CreateCollectionWithVectorizer - var articleCollection = new Collection - { - Name = collectionName, - Description = "something", - Properties = [Property.Int("number_property"), Property.Text("test_property")], - VectorConfig = new VectorConfig("vector_name", new Vectorizer.Text2VecContextionary(), new VectorIndex.HNSW()) - }; - - var collection = await client.Collections.Create(articleCollection); - // END CreateCollectionWithVectorizer - Console.WriteLine($"Successfully created collection: '{collectionName}'"); - } - - // [Fact] - public async Task Should_Delete_Collection() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - var collectionName = "Article"; - - // Ensure the collection exists before attempting to delete it - if (await client.Collections.Exists(collectionName)) - { - await client.Collections.Delete(collectionName); - Console.WriteLine($"Successfully deleted collection: '{collectionName}'"); - } - else - { - Console.WriteLine($"Collection '{collectionName}' does not exist."); - } - } -} diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTests.cs index fccfcf624..12c931b16 100644 --- a/_includes/code/csharp/ConnectionTests.cs +++ b/_includes/code/csharp/ConnectionTests.cs @@ -53,7 +53,7 @@ public async Task Should_Perform_Custom_Connection_With_ApiKey() UseSsl: true, // Whether to use https (secure) for the HTTP API connection GrpcAddress: grpcHost, // Hostname for the gRPC API connection GrpcPort: 443, // Default is 50051, WCD uses 443 - ApiKey: weaviateApiKey // API key for authentication + Credentials: Auth.ApiKey(weaviateApiKey) // API key for authentication ); var client = new WeaviateClient(config); // END CustomConnect @@ -134,7 +134,7 @@ public async Task Should_Connect_Locally_With_Auth() restPort: 8099, grpcPort: 50052, useSsl: true, - apiKey: localApiKey + credentials: localApiKey ); // END LocalAuth diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTests.cs index 138bb39cc..cf73cc882 100644 --- a/_includes/code/csharp/ManageCollectionsTests.cs +++ b/_includes/code/csharp/ManageCollectionsTests.cs @@ -356,7 +356,7 @@ public async Task ConfigurePropertyModuleSettings() // START AddNamedVectors CollectionClient articles = weaviate.Collections.Use(collectionName); // TODO[g-despot]: AddVector throws error: vectorizer config of vector \"default\" is immutable - await articles.Config.AddVector(Configure.Vectors.Text2VecCohere().New("body_vector", properties: "body")); + await articles.Config.AddVector(Configure.Vectors.Text2VecCohere().New("body_vector", sourceProperties: "body")); // TODO[g-despot]: Missing sourceProperties // Configure.Vectors.Text2VecCohere(sourceProperties: new[] { "body" }).New("body_vector") // Configure.Vectors.Text2VecCohere().New("body_vector") @@ -516,7 +516,7 @@ await articles.Config.Update(c => c.Description = "An updated collection description."; // TODO[g-despot]: Updating property descriptions is missing c.InvertedIndexConfig.Bm25.K1 = 1.5f; - + VectorConfigUpdate vectorConfig = c.VectorConfig["default"]; vectorConfig.VectorIndexConfig.UpdateHNSW(vic => { diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageDataTests.cs index 71838692d..98b8783b5 100644 --- a/_includes/code/csharp/ManageDataTests.cs +++ b/_includes/code/csharp/ManageDataTests.cs @@ -173,7 +173,7 @@ public async Task CreateObjectNamedVectors() // CreateObjectNamedVectors END // Test - var result = await reviews.Query.FetchObjectByID(uuid, metadata: MetadataOptions.Vector); + var result = await reviews.Query.FetchObjectByID(uuid, returnMetadata: MetadataOptions.Vector); Assert.NotNull(result?.Vectors); Assert.Equal(3, result.Vectors.Count); Assert.True(result.Vectors.ContainsKey("title")); @@ -206,7 +206,7 @@ public async Task CreateObjectWithDeterministicId() // Test Assert.Equal(GenerateUuid5(dataObject), uuid); - await jeopardy.Data.Delete(uuid); // Clean up + await jeopardy.Data.DeleteByID(uuid); // Clean up } [Fact] @@ -251,7 +251,7 @@ await publications.Data.Insert( ); // END WithGeoCoordinates - var response = await publications.Query.List( + var response = await publications.Query.FetchObjects( filter: Filter.Property("headquartersGeoLocation") .WithinGeoRange( new GeoCoordinateConstraint(52.39f, 4.84f, 1000) @@ -260,7 +260,7 @@ await publications.Data.Insert( Assert.Single(response.Objects); var objUuid = response.Objects.First().ID; - await publications.Data.Delete((Guid)objUuid); + await publications.Data.DeleteByID((Guid)objUuid); } [Fact] @@ -290,7 +290,7 @@ await authorsCollection.Data.Insert( // END CheckForAnObject Assert.True(authorExists); - await authorsCollection.Data.Delete(objectUuid); + await authorsCollection.Data.DeleteByID(objectUuid); var deletedAuthor = await authorsCollection.Query.FetchObjectByID(objectUuid); Assert.Null(deletedAuthor); } diff --git a/_includes/code/csharp/ObjectTests.cs b/_includes/code/csharp/ObjectTests.cs deleted file mode 100644 index adf8ec4bc..000000000 --- a/_includes/code/csharp/ObjectTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Xunit; -using Weaviate.Client; -using System; -using System.Threading.Tasks; -using Weaviate.Client.Models; - -namespace WeaviateProject.Tests; - -public class ObjectTest -{ - readonly Guid objectId = Guid.NewGuid(); - readonly string collectionName = "Jeopardy"; - - // [Fact] - public async Task Should_Import_Objects() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - // START CreateObject - var collectionClient = client.Collections.Use(collectionName); - - var obj = await collectionClient.Data.Insert( - new - { - question = "This vector DB is OSS & supports automatic property type inference on import", - // "answer": "Weaviate", # properties can be omitted - newProperty = 123 - }, - id: objectId - ); - // END CreateObject - Console.WriteLine($"Successfully created collection: '{collectionName}'"); - } - - // [Fact] - public async Task Should_Delete_Objects() - { - var client = Connect.Local(restPort: 8080, grpcPort: 50051); - - if (await client.Collections.Exists(collectionName)) - { - // START DeleteObject - var collection = client.Collections.Use(collectionName); - await collection.Data.Delete(objectId); - // END DeleteObject - Console.WriteLine($"Successfully deleted object: '{objectId}' from collection: '{collectionName}'"); - } - else - { - Console.WriteLine($"Collection '{collectionName}' does not exist."); - } - } -} diff --git a/_includes/code/csharp/SearchBasicsTests.cs b/_includes/code/csharp/SearchBasicsTests.cs new file mode 100644 index 000000000..28a6dc2a2 --- /dev/null +++ b/_includes/code/csharp/SearchBasicsTests.cs @@ -0,0 +1,260 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Text.Json; +using System.Linq; + +// Note: This code assumes the existence of a Weaviate instance populated +// with 'JeopardyQuestion' and 'WineReviewMT' collections as per the Python examples. +public class SearchBasicsTests : IAsyncLifetime +{ + private WeaviateClient client; + + public Task InitializeAsync() + { + // ================================ + // ===== INSTANTIATION-COMMON ===== + // ================================ + + // Best practice: store your credentials in environment variables + var weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL"); + var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + var openaiApiKey = Environment.GetEnvironmentVariable("OPENAI_APIKEY"); + + // The Connect.Cloud helper method is a straightforward way to connect. + // We add the OpenAI API key to the headers for the text2vec-openai module. + client = Connect.Cloud( + weaviateUrl, + weaviateApiKey + ); + + return Task.CompletedTask; + } + + public Task DisposeAsync() + { + // The C# client manages its connections automatically and does not require an explicit 'close' method. + return Task.CompletedTask; + } + + [Fact] + public async Task BasicGet() + { + // ============================== + // ===== BASIC GET EXAMPLES ===== + // ============================== + + // BasicGetPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // highlight-start + var response = await jeopardy.Query.FetchObjects(); + // highlight-end + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END BasicGetPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + } + + [Fact] + public async Task GetWithLimit() + { + // ==================================== + // ===== BASIC GET LIMIT EXAMPLES ===== + // ==================================== + + // GetWithLimitPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + // highlight-start + limit: 1 + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END GetWithLimitPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.Single(response.Objects); + } + + [Fact] + public async Task GetProperties() + { + // ========================================== + // ===== GET OBJECT PROPERTIES EXAMPLES ===== + // ========================================== + + // GetPropertiesPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + // highlight-start + limit: 1, + returnProperties: new[] { "question", "answer", "points" } + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END GetPropertiesPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + foreach (var propName in new[] { "question", "answer", "points" }) + { + Assert.True(response.Objects.First().Properties.ContainsKey(propName)); + } + } + + [Fact] + public async Task GetObjectVector() + { + // ====================================== + // ===== GET OBJECT VECTOR EXAMPLES ===== + // ====================================== + + // GetObjectVectorPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + // highlight-start + returnMetadata: MetadataOptions.Vector, + // highlight-end + limit: 1 + ); + + // Note: The C# client returns a dictionary of named vectors. + // We assume the default vector name is 'default'. + Console.WriteLine(JsonSerializer.Serialize(response.Objects.First().Vectors["default"])); + // END GetObjectVectorPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.IsType(response.Objects.First().Vectors["default"]); + } + + [Fact] + public async Task GetObjectId() + { + // ================================== + // ===== GET OBJECT ID EXAMPLES ===== + // ================================== + + // GetObjectIdPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + // Object IDs are included by default with the Weaviate C# client! :) + limit: 1 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(o.ID); + } + // END GetObjectIdPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.IsType(response.Objects.First().ID); + } + + [Fact] + public async Task GetWithCrossRefs() + { + // ============================== + // ===== GET WITH CROSS-REF EXAMPLES ===== + // ============================== + //TODO + // GetWithCrossRefsPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + // highlight-start + returnReferences: new[] { + new QueryReference( + linkOn: "hasCategory" + //returnProperties: "title" + ) + }, + // highlight-end + limit: 2 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(o.Properties["question"]); + // print referenced objects + // Note: References are grouped by property name ('hasCategory') + foreach (var refObj in o.References["hasCategory"]) + { + Console.WriteLine(JsonSerializer.Serialize(refObj.Properties)); + } + } + // END GetWithCrossRefsPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().References["hasCategory"].Count > 0); + } + + [Fact] + public async Task GetWithMetadata() + { + // ==================================== + // ===== GET WITH METADATA EXAMPLE ===== + // ==================================== + + // GetWithMetadataPython + var jeopardy = client.Collections.Use>("JeopardyQuestion"); + var response = await jeopardy.Query.FetchObjects( + limit: 1, + // highlight-start + returnMetadata: MetadataOptions.CreationTime + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); // View the returned properties + Console.WriteLine(o.Metadata.CreationTime); // View the returned creation time + } + // END GetWithMetadataPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.NotNull(response.Objects.First().Metadata.CreationTime); + } + + [Fact] + public async Task MultiTenancyGet() + { + // ========================= + // ===== MULTI-TENANCY ===== + // ========================= + + // MultiTenancy + var mtCollection = client.Collections.Use>("WineReviewMT"); + + // In the C# client, the tenant is specified directly in the query method + // rather than creating a separate tenant-specific collection object. + // highlight-start + var response = await mtCollection.Query.FetchObjects( + tenant: "tenantA", + // highlight-end + returnProperties: new[] { "review_body", "title" }, + limit: 1 + ); + + Console.WriteLine(JsonSerializer.Serialize(response.Objects.First().Properties)); + // END MultiTenancy + + Assert.True(response.Objects.Count() > 0); + Assert.Equal("WineReviewMT", response.Objects.First().Collection); + } +} \ No newline at end of file diff --git a/_includes/code/csharp/SearchTests.cs b/_includes/code/csharp/SearchTests.cs deleted file mode 100644 index 1a93406cd..000000000 --- a/_includes/code/csharp/SearchTests.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Xunit; -using Weaviate.Client; -using System; -using System.Threading.Tasks; -using Weaviate.Client.Models; -using System.Linq; - -namespace WeaviateProject.Tests; - -public static class QueryConstants -{ - public const string NearTextQuery = "Weaviate"; -} - -public class SearchTest -{ - readonly WeaviateClient client = Connect.Local(restPort: 8080, grpcPort: 50051); - - // [Fact] - public async Task Should_Fetch_By_Id() - { - var collection = client.Collections.Use("JeopardyQuestion"); - var objectId = Guid.NewGuid(); - await collection.Data.Insert( - new - { - question = "This vector DB is OSS & supports automatic property type inference on import", - newProperty = 123 - }, - id: objectId - ); - - // START FetchById - var obj = await collection.Query.FetchObjectByID(objectId); - Console.WriteLine($"Fetched object with ID: {obj.ID}"); - // END FetchById - } - - // [Fact] - public async Task Should_Near_Text() - { - // START GetNearText - var collection = client.Collections.Use("JeopardyQuestion"); - var queryResult = await collection.Query.NearText( - "animals in movies", - limit: 1, - metadata: MetadataOptions.Distance); - - Console.WriteLine("Search Results:"); - foreach (var obj in queryResult.Objects) - { - Console.WriteLine($"Object: {obj.Properties})"); - } - // END GetNearText - } -} diff --git a/_includes/code/csharp/WeaviateProject.Tests.csproj b/_includes/code/csharp/WeaviateProject.Tests.csproj index accde3e72..a20a0396a 100644 --- a/_includes/code/csharp/WeaviateProject.Tests.csproj +++ b/_includes/code/csharp/WeaviateProject.Tests.csproj @@ -9,7 +9,8 @@ - + + From 4e2e536d3a0288877b2442e411cf9c80d1469f2a Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:28:51 +0200 Subject: [PATCH 11/18] Update code --- _includes/code/csharp/HybridSearchTests.cs | 472 ++++++++++++++++++ _includes/code/csharp/ImageSearchTests.cs | 161 ++++++ _includes/code/csharp/KeywordSearchTests.cs | 295 +++++++++++ .../code/csharp/ManageCollectionsTests.cs | 5 +- _includes/code/csharp/SearchBasicsTests.cs | 15 +- .../code/csharp/SimilaritySearchTests.cs | 332 ++++++++++++ .../manage-collections/vector-config.mdx | 2 +- docs/weaviate/manage-objects/create.mdx | 2 +- docs/weaviate/manage-objects/delete.mdx | 2 +- docs/weaviate/search/basics.md | 2 +- docs/weaviate/search/similarity.md | 2 +- 11 files changed, 1274 insertions(+), 16 deletions(-) create mode 100644 _includes/code/csharp/HybridSearchTests.cs create mode 100644 _includes/code/csharp/ImageSearchTests.cs create mode 100644 _includes/code/csharp/KeywordSearchTests.cs create mode 100644 _includes/code/csharp/SimilaritySearchTests.cs diff --git a/_includes/code/csharp/HybridSearchTests.cs b/_includes/code/csharp/HybridSearchTests.cs new file mode 100644 index 000000000..030c15f33 --- /dev/null +++ b/_includes/code/csharp/HybridSearchTests.cs @@ -0,0 +1,472 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Text.Json; +using System.Linq; + +// Note: This code assumes the existence of a Weaviate instance populated +// with 'JeopardyQuestion' and 'WineReviewNV' collections as per the Python examples. +public class HybridSearchTests : IAsyncLifetime +{ + private WeaviateClient client; + + public Task InitializeAsync() + { + // ================================ + // ===== INSTANTIATION-COMMON ===== + // ================================ + + // Best practice: store your credentials in environment variables + var weaviateUrl = Environment.GetEnvironmentVariable("WEAVATE_URL"); + var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVATE_API_KEY"); + var openaiApiKey = Environment.GetEnvironmentVariable("OPENAI_APIKEY"); + + client = Connect.Cloud( + weaviateUrl, + weaviateApiKey + //additionalHeaders: new Dictionary { { "X-OpenAI-Api-Key", openaiApiKey } } + ); + return Task.CompletedTask; + } + + public Task DisposeAsync() + { + // The C# client manages its connections automatically and does not require an explicit 'close' method. + return Task.CompletedTask; + } + + [Fact] + public async Task NamedVectorHybrid() + { + // ============================== + // ===== Named Vector Hybrid Query ===== + // ============================== + + // NamedVectorHybridPython + var reviews = client.Collections.Use("WineReviewNV"); + // highlight-start + var response = await reviews.Query.Hybrid( + "A French Riesling", + targetVector: ["title_country"], + limit: 3 + ); + // highlight-end + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END NamedVectorHybridPython + + Assert.Equal("WineReviewNV", response.Objects.First().Collection); + } + + [Fact] + public async Task BasicHybrid() + { + // ============================== + // ===== Basic Hybrid Query ===== + // ============================== + + // HybridBasicPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // highlight-start + var response = await jeopardy.Query.Hybrid("food", limit: 3); + // highlight-end + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridBasicPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithScore() + { + // ======================================= + // ===== Hybrid Query with the Score ===== + // ======================================= + + // HybridWithScorePython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + alpha: 0.5f, + // highlight-start + returnMetadata: MetadataOptions.Score | MetadataOptions.ExplainScore, + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + // highlight-start + Console.WriteLine($"Score: {o.Metadata.Score}, Explain Score: {o.Metadata.ExplainScore}"); + // highlight-end + } + // END HybridWithScorePython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.NotNull(response.Objects.First().Metadata.Score); + Assert.NotNull(response.Objects.First().Metadata.ExplainScore); + } + + [Fact] + public async Task HybridWithLimitAndOffset() + { + // =================================== + // ===== Hybrid Query with limit ===== + // =================================== + + // START limit Python + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + limit: 3, + offset: 1 + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END limit Python + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal(3, response.Objects.Count()); + } + + [Fact] + public async Task HybridWithAutocut() + { + // ===================================== + // ===== Hybrid Query with autocut ===== + // ===================================== + + // START autocut Python + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + fusionType: HybridFusion.Ranked, + autoLimit: 1 + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END autocut Python + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithAlpha() + { + // =================================== + // ===== Hybrid Query with Alpha ===== + // =================================== + + // HybridWithAlphaPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + alpha: 0.25f, + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithAlphaPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithFusionType() + { + // ======================================== + // ===== Hybrid Query with FusionType ===== + // ======================================== + + // HybridWithFusionTypePython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + fusionType: HybridFusion.RelativeScore, + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithFusionTypePython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithBM25OperatorOr() + { + // ======================================== + // ===== Hybrid Query with BM25 Operator (Or) ===== + // ======================================== + + // START HybridWithBM25OperatorOrWithMin + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + // highlight-start + "Australian mammal cute", + bm25Operator: new BM25Operator.Or(MinimumMatch: 2), + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithBM25OperatorOrWithMin + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithBM25OperatorAnd() + { + // ======================================== + // ===== Hybrid Query with BM25 Operator (And) ===== + // ======================================== + + // START HybridWithBM25OperatorAnd + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + // highlight-start + "Australian mammal cute", + bm25Operator: new BM25Operator.And(), // Each result must include all tokens + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithBM25OperatorAnd + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithProperties() + { + // ================================================== + // ===== Hybrid Query with Properties Specified ===== + // ================================================== + + // HybridWithPropertiesPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + queryProperties: new[] { "question" }, + // highlight-end + alpha: 0.25f, + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithPropertiesPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithPropertyWeighting() + { + // ==================================================== + // ===== Hybrid Query with Properties & Weighting ===== + // ==================================================== + + // HybridWithPropertyWeightingPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + queryProperties: new[] { "question^2", "answer" }, + // highlight-end + alpha: 0.25f, + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithPropertyWeightingPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithVector() + { + // ==================================== + // ===== Hybrid Query With Vector ===== + // ==================================== + + // HybridWithVectorPython + var queryVector = Enumerable.Repeat(-0.02f, 1536).ToArray(); + + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // TODO[g-despot] Why is name required in VectorData.Create? + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + vectors: VectorData.Create("default", queryVector), + // highlight-end + alpha: 0.25f, + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithVectorPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + } + + [Fact] + public async Task HybridWithFilter() + { + // =================================== + // ===== Hybrid Query with Where ===== + // =================================== + + // HybridWithFilterPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "food", + // highlight-start + filters: Filter.Property("round").Equal("Double Jeopardy!"), + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END HybridWithFilterPython + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal("Double Jeopardy!", response.Objects.First().Properties["round"].ToString()); + } + + [Fact] + public async Task HybridWithVectorParameters() + { + // ========================================= + // ===== Hybrid with vector parameters ===== + // ========================================= + + // START VectorParametersPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "California", + // highlight-start + maxVectorDistance: 0.4f, // Maximum threshold for the vector search component + vectors: new HybridNearText( + "large animal", + MoveAway: new Move(force: 0.5f, concepts: ["mammal", "terrestrial"]) + ), + // highlight-end + alpha: 0.75f, + limit: 5 + ); + // END VectorParametersPython + + Assert.True(response.Objects.Count() <= 5); + Assert.True(response.Objects.Count() > 0); + } + + [Fact] + public async Task HybridWithVectorSimilarity() + { + // ========================================= + // ===== Hybrid with vector similarity threshold ===== + // ========================================= + + // START VectorSimilarityPython + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "California", + // highlight-start + maxVectorDistance: 0.4f, // Maximum threshold for the vector search component + // highlight-end + alpha: 0.75f, + limit: 5 + ); + // END VectorSimilarityPython + + Assert.True(response.Objects.Count() <= 5); + Assert.True(response.Objects.Count() > 0); + } + + [Fact] + public async Task HybridWithGroupBy() + { + // ========================================= + // ===== Hybrid with groupBy ===== + // ========================================= + + // START HybridGroupByPy4 + // Grouping parameters + var groupBy = new GroupByRequest + { + PropertyName = "round", // group by this property + ObjectsPerGroup = 3, // maximum objects per group + NumberOfGroups = 2, // maximum number of groups + }; + + // Query + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.Hybrid( + "California", + alpha: 0.75f, + groupBy: groupBy + ); + + foreach (var grp in response.Groups.Values) + { + Console.WriteLine($"{grp.Name} {JsonSerializer.Serialize(grp.Objects)}"); + } + // END HybridGroupByPy4 + + Assert.True(response.Groups.Count <= 2); + Assert.True(response.Groups.Count > 0); + } +} \ No newline at end of file diff --git a/_includes/code/csharp/ImageSearchTests.cs b/_includes/code/csharp/ImageSearchTests.cs new file mode 100644 index 000000000..a413bab65 --- /dev/null +++ b/_includes/code/csharp/ImageSearchTests.cs @@ -0,0 +1,161 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Text.Json; +using System.Linq; +using System.IO; +using System.Net.Http; +using System.Text; + +// Note: This code assumes a local Weaviate instance is running and has the 'Dog' collection +// imported, as per the weaviate-examples GitHub repository. +// It also assumes an image file exists at "./images/search-image.jpg" for some tests. +public class ImageSearchTests : IAsyncLifetime +{ + private WeaviateClient client; + + public Task InitializeAsync() + { + client = Connect.Local(); + return Task.CompletedTask; + } + + public Task DisposeAsync() + { + // START-ANY + // The C# client manages its connections automatically and does not require an explicit 'close' method. + // END-ANY + return Task.CompletedTask; + } + + // ================================================= + // ===== Helper functions to convert to base64 ===== + // ================================================= + + // START helper base64 functions + private static async Task UrlToBase64(string url) + { + using var httpClient = new HttpClient(); + var imageBytes = await httpClient.GetByteArrayAsync(url); + return Convert.ToBase64String(imageBytes); + } + // END helper base64 functions + + [Fact] + public async Task SearchWithBase64() + { + // =========================================== + // ===== Search by base64 representation ===== + // =========================================== + + // Using the helper function to get a real Base64 image string for the test + var base64Img = await UrlToBase64("https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Deutsches_Museum_Portrait_4.jpg/500px-Deutsches_Museum_Portrait_4.jpg"); + + // START search with base64 + // highlight-start + var base64_string = base64Img; + // highlight-end + + // Convert base64 string to byte array + var imageBytes = Convert.FromBase64String(base64_string); + + // Get the collection containing images + var dogs = client.Collections.Use("Dog"); + + // Perform query + // highlight-start + var response = await dogs.Query.NearImage( + imageBytes, + // highlight-end + returnProperties: new[] { "breed" }, + limit: 1 + // targetVector: "vector_name" // required when using multiple named vectors + ); + + Console.WriteLine(JsonSerializer.Serialize(response.Objects.FirstOrDefault())); + // END search with base64 + + Assert.NotNull(response.Objects.FirstOrDefault()); + // A more robust test would check for a specific expected breed, + // but this depends heavily on the dataset and vectorizer used. + Assert.True(response.Objects.First().Properties.ContainsKey("breed")); + } + + [Fact] + public async Task SearchWithImageFile() + { + // ==================================== + // ===== Search by image filename ===== + // ==================================== + + // This test requires a file named 'search-image.jpg' inside an 'images' folder. + var imagePath = Path.Combine("images", "search-image.jpg"); + if (!File.Exists(imagePath)) + { + // Skip test if the image file doesn't exist. + Assert.True(false, $"Image file not found at {imagePath}. Skipping test."); + return; + } + + // START ImageFileSearch + var dogs = client.Collections.Use("Dog"); + // Read the image file into a byte array + var imageBytes = await File.ReadAllBytesAsync(imagePath); + var response = await dogs.Query.NearImage( + // highlight-start + imageBytes, // Provide image bytes + // highlight-end + returnProperties: new[] { "breed" }, + limit: 1 + // targetVector: "vector_name" // required when using multiple named vectors + ); + + Console.WriteLine(JsonSerializer.Serialize(response.Objects.FirstOrDefault())); + // END ImageFileSearch + + Assert.NotNull(response.Objects.FirstOrDefault()); + Assert.True(response.Objects.First().Properties.ContainsKey("breed")); + } + + [Fact] + public async Task SearchWithDistance() + { + // ============================ + // ===== Maximum distance ===== + // ============================ + + // This test requires a file named 'search-image.jpg' inside an 'images' folder. + var imagePath = Path.Combine("images", "search-image.jpg"); + if (!File.Exists(imagePath)) + { + // Skip test if the image file doesn't exist. + Assert.True(false, $"Image file not found at {imagePath}. Skipping test."); + return; + } + + // START Distance + var dogs = client.Collections.Use("Dog"); + var imageBytes = await File.ReadAllBytesAsync(imagePath); + var response = await dogs.Query.NearImage( + imageBytes, + // highlight-start + distance: 0.8f, // Maximum accepted distance + returnMetadata: MetadataOptions.Distance, // return distance from the source image + // highlight-end + returnProperties: new[] { "breed" }, + limit: 5 + ); + + foreach (var item in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(item)); + } + // END Distance + + Assert.NotEmpty(response.Objects); + Assert.NotNull(response.Objects.First().Metadata.Distance); + Assert.True(response.Objects.First().Metadata.Distance < 0.8f); + } +} \ No newline at end of file diff --git a/_includes/code/csharp/KeywordSearchTests.cs b/_includes/code/csharp/KeywordSearchTests.cs new file mode 100644 index 000000000..f14daefbe --- /dev/null +++ b/_includes/code/csharp/KeywordSearchTests.cs @@ -0,0 +1,295 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Text.Json; +using System.Linq; + +public class KeywordSearchTests : IAsyncLifetime +{ + private WeaviateClient client; + + public Task InitializeAsync() + { + // ================================ + // ===== INSTANTIATION-COMMON ===== + // ================================ + + // Best practice: store your credentials in environment variables + var weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL"); + var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + var openaiApiKey = Environment.GetEnvironmentVariable("OPENAI_APIKEY"); + + client = Connect.Cloud( + weaviateUrl, + weaviateApiKey + //additionalHeaders: new Dictionary { { "X-OpenAI-Api-Key", openaiApiKey } } + ); + return Task.CompletedTask; + } + + public Task DisposeAsync() + { + // The C# client manages its connections automatically and does not require an explicit 'close' method. + return Task.CompletedTask; + } + + [Fact] + public async Task BasicBM25() + { + // ============================ + // ===== Basic BM25 Query ===== + // ============================ + + // BM25Basic + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // highlight-start + var response = await jeopardy.Query.BM25( + // highlight-end + "food", + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END BM25Basic + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("food", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + } + + [Fact] + public async Task BM25WithScore() + { + // ================================================ + // ===== BM25 Query with score / explainScore ===== + // ================================================ + + // BM25WithScore + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + "food", + returnMetadata: MetadataOptions.Score, + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + // highlight-start + Console.WriteLine(o.Metadata.Score); + // highlight-end + } + // END BM25WithScore + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("food", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + Assert.NotNull(response.Objects.First().Metadata.Score); + } + + [Fact] + public async Task BM25WithLimit() + { + // ================================= + // ===== BM25 Query with limit ===== + // ================================= + + // START limit + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + "safety", + // highlight-start + limit: 3, + offset: 1 + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END limit + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("safety", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + Assert.Equal(3, response.Objects.Count()); + } + + [Fact] + public async Task BM25WithAutocut() + { + // =================================== + // ===== BM25 Query with autocut ===== + // =================================== + + // START autocut + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + "safety", + // highlight-start + autoCut: 1 + // highlight-end + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END autocut + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("safety", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + } + + [Fact] + public async Task BM25WithProperties() + { + // =============================================== + // ===== BM25 Query with Selected Properties ===== + // =============================================== + + // BM25WithProperties + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + "safety", + // highlight-start + searchFields: new[] { "question" }, + // highlight-end + returnMetadata: MetadataOptions.Score, + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Score); + } + // END BM25WithProperties + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("safety", response.Objects.First().Properties["question"].ToString().ToLower()); + } + + [Fact] + public async Task BM25WithBoostedProperties() + { + // ============================================== + // ===== BM25 Query with Boosted Properties ===== + // ============================================== + + // BM25WithBoostedProperties + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + "food", + // highlight-start + searchFields: new[] { "question^2", "answer" }, + // highlight-end + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END BM25WithBoostedProperties + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("food", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + } + + [Fact] + public async Task BM25MultipleKeywords() + { + // ================================== + // ===== BM25 multiple keywords ===== + // ================================== + + // START MultipleKeywords + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.BM25( + // highlight-start + "food wine", // search for food or wine + // highlight-end + searchFields: new[] { "question" }, + limit: 5 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(o.Properties["question"]); + } + // END MultipleKeywords + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + var propertiesJson = JsonSerializer.Serialize(response.Objects.First().Properties).ToLower(); + Assert.True(propertiesJson.Contains("food") || propertiesJson.Contains("wine")); + } + + [Fact] + public async Task BM25WithFilter() + { + // ================================== + // ===== Basic BM25 With Filter ===== + // ================================== + + // BM25WithFilter + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // TODO[g-despot]: Filters missing? + var response = await jeopardy.Query.BM25( + "food", + // highlight-start + filter: Filter.Property("round").Equal("Double Jeopardy!"), + // highlight-end + returnProperties: new[] { "answer", "question", "round" }, // return these properties + limit: 3 + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + } + // END BM25WithFilter + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Contains("food", JsonSerializer.Serialize(response.Objects.First().Properties).ToLower()); + Assert.Equal("Double Jeopardy!", response.Objects.First().Properties["round"].ToString()); + } + + [Fact] + public async Task BM25WithGroupBy() + { + // ================================== + // ===== BM25 groupBy ===== + // ================================== + + // START BM25GroupByPy4 + var jeopardy = client.Collections.Use("JeopardyQuestion"); + + // Grouping parameters + var groupBy = new GroupByRequest + { + PropertyName = "round", // group by this property + ObjectsPerGroup = 3, // maximum objects per group + NumberOfGroups = 2, // maximum number of groups + }; + + // Query + var response = await jeopardy.Query.BM25( + "California", + groupBy: groupBy + ); + + foreach (var grp in response.Groups.Values) + { + Console.WriteLine($"{grp.Name} {JsonSerializer.Serialize(grp.Objects)}"); + } + // END BM25GroupByPy4 + + Assert.True(response.Groups.Count > 0); + Assert.True(response.Groups.Count <= 2); + } +} \ No newline at end of file diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTests.cs index cf73cc882..3df7ac199 100644 --- a/_includes/code/csharp/ManageCollectionsTests.cs +++ b/_includes/code/csharp/ManageCollectionsTests.cs @@ -466,8 +466,7 @@ public async Task ConfigureMultiTenancyAndProperties() // START AddProperty CollectionClient articles = weaviate.Collections.Use(collectionName); - // TODO[g-despot]: AddProperty is internal - // await articles.Config.AddProperty(Property.Text("body")); + await articles.Config.AddProperty(Property.Text("body")); // END AddProperty config = await weaviate.Collections.Export(collectionName); @@ -514,7 +513,6 @@ public async Task Should_Update_Collection_Configuration() await articles.Config.Update(c => { c.Description = "An updated collection description."; - // TODO[g-despot]: Updating property descriptions is missing c.InvertedIndexConfig.Bm25.K1 = 1.5f; VectorConfigUpdate vectorConfig = c.VectorConfig["default"]; @@ -554,7 +552,6 @@ public async Task ReadAndDeleteCollections() Assert.Equal(collectionName, articlesConfig.Name); // START ReadAllCollections - // TODO[g-despot]: Strange error: System.ArgumentException : Unsupported vectorizer type: text2colbert-jinaai (Parameter 'type') await foreach (Collection collection in weaviate.Collections.List()) { Console.WriteLine(collection.Name); diff --git a/_includes/code/csharp/SearchBasicsTests.cs b/_includes/code/csharp/SearchBasicsTests.cs index 28a6dc2a2..4ac23d28c 100644 --- a/_includes/code/csharp/SearchBasicsTests.cs +++ b/_includes/code/csharp/SearchBasicsTests.cs @@ -129,14 +129,16 @@ public async Task GetObjectVector() var jeopardy = client.Collections.Use>("JeopardyQuestion"); var response = await jeopardy.Query.FetchObjects( // highlight-start - returnMetadata: MetadataOptions.Vector, + returnMetadata: (MetadataOptions.Vector, ["default"]), // highlight-end limit: 1 ); // Note: The C# client returns a dictionary of named vectors. // We assume the default vector name is 'default'. - Console.WriteLine(JsonSerializer.Serialize(response.Objects.First().Vectors["default"])); + //TODO[g-despot]: Why is vector not returned? + Console.WriteLine("Vector for 'default':"); + Console.WriteLine(JsonSerializer.Serialize(response.Objects.First())); // END GetObjectVectorPython Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); @@ -173,17 +175,16 @@ public async Task GetWithCrossRefs() // ============================== // ===== GET WITH CROSS-REF EXAMPLES ===== // ============================== - //TODO // GetWithCrossRefsPython var jeopardy = client.Collections.Use>("JeopardyQuestion"); var response = await jeopardy.Query.FetchObjects( // highlight-start - returnReferences: new[] { + returnReferences: [ new QueryReference( - linkOn: "hasCategory" - //returnProperties: "title" + linkOn: "hasCategory", + fields: ["title"] ) - }, + ], // highlight-end limit: 2 ); diff --git a/_includes/code/csharp/SimilaritySearchTests.cs b/_includes/code/csharp/SimilaritySearchTests.cs new file mode 100644 index 000000000..7a2062f68 --- /dev/null +++ b/_includes/code/csharp/SimilaritySearchTests.cs @@ -0,0 +1,332 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Text.Json; +using System.Linq; + +public class SemanticSearchTests : IAsyncLifetime +{ + private WeaviateClient client; + + public Task InitializeAsync() + { + // ================================ + // ===== INSTANTIATION-COMMON ===== + // ================================ + + // Best practice: store your credentials in environment variables + var weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL"); + var weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY"); + var openaiApiKey = Environment.GetEnvironmentVariable("OPENAI_APIKEY"); + var cohereApiKey = Environment.GetEnvironmentVariable("COHERE_APIKEY"); + + client = Connect.Cloud( + weaviateUrl, + weaviateApiKey + // additionalHeaders: new Dictionary + // { + // { "X-OpenAI-Api-Key", openaiApiKey }, + // { "X-Cohere-Api-Key", cohereApiKey } + // } + ); + return Task.CompletedTask; + } + + public Task DisposeAsync() + { + // The C# client manages its connections automatically and does not require an explicit 'close' method. + return Task.CompletedTask; + } + + [Fact] + public async Task NamedVectorNearText() + { + // =============================================== + // ===== QUERY WITH TARGET VECTOR & nearText ===== + // =============================================== + + // NamedVectorNearText + var reviews = client.Collections.Use("WineReviewNV"); + // TODO[g-despot] Why is groupBy necessary here? + var response = await reviews.Query.NearText( + "a sweet German white wine", + limit: 2, + // highlight-start + targetVector: ["title_country"], // Specify the target vector for named vector collections + // highlight-end + returnMetadata: MetadataOptions.Distance, + groupBy: new GroupByRequest + { + PropertyName = "country", // group by this property + ObjectsPerGroup = 1, // maximum objects per group + NumberOfGroups = 2, // maximum number of groups + } + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END NamedVectorNearText + + Assert.Equal("WineReviewNV", response.Objects.First().Collection); + Assert.Equal(2, response.Objects.Count()); + Assert.True(response.Objects.First().Properties.ContainsKey("title")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } + + [Fact] + public async Task GetNearText() + { + // =============================== + // ===== QUERY WITH nearText ===== + // =============================== + + // GetNearText + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // highlight-start + var response = await jeopardy.Query.NearText( + "animals in movies" + // highlight-end + , + limit: 2, + returnMetadata: MetadataOptions.Distance + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END GetNearText + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal(2, response.Objects.Count()); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } + + [Fact] + public async Task GetNearObject() + { + // ================================= + // ===== QUERY WITH nearObject ===== + // ================================= + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var objects = await jeopardy.Query.FetchObjects(limit: 1); + var uuid = objects.Objects.First().ID; + + // GetNearObject + // highlight-start + var response = await jeopardy.Query.NearObject( + (Guid)uuid, // A UUID of an object + // highlight-end + limit: 2, + returnMetadata: MetadataOptions.Distance + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END GetNearObject + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal(2, response.Objects.Count()); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } + + [Fact] + public async Task GetNearVector() + { + // ================================= + // ===== QUERY WITH nearVector ===== + // ================================= + + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var objectWithVector = await jeopardy.Query.FetchObjects(limit: 1, returnMetadata: MetadataOptions.Vector); + var queryVector = objectWithVector.Objects.First().Vectors["default"]; + + // GetNearVector + // highlight-start + var response = await jeopardy.Query.NearVector( + VectorData.Create("default", queryVector), // your query vector goes here + // highlight-end + limit: 2, + returnMetadata: MetadataOptions.Distance + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END GetNearVector + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal(2, response.Objects.Count()); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } + + [Fact] + public async Task GetWithDistance() + { + // =============================== + // ===== QUERY WITH DISTANCE ===== + // =============================== + + // GetWithDistance + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.NearText( + "animals in movies", + // highlight-start + distance: 0.25f, // max accepted distance + // highlight-end + returnMetadata: MetadataOptions.Distance + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END GetWithDistance + + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + foreach (var o in response.Objects) + { + Assert.True(o.Metadata.Distance < 0.25f); + } + } + + [Fact] + public async Task GetWithAutocut() + { + // =============================== + // ===== Query with autocut ===== + // =============================== + + // START Autocut + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.NearText( + "animals in movies", + // highlight-start + autoCut: 1, // number of close groups + // highlight-end + returnMetadata: MetadataOptions.Distance, + // TODO[g-despot]: Why is groupBy necessary here? + groupBy: new GroupByRequest + { + PropertyName = "round", // group by this property + ObjectsPerGroup = 2, // maximum objects per group + NumberOfGroups = 2, // maximum number of groups + } + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END Autocut + + Assert.True(response.Objects.Count() > 0); + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } + + [Fact] + public async Task GetWithGroupBy() + { + // ============================== + // ===== QUERY WITH groupBy ===== + // ============================== + + // GetWithGroupby + var jeopardy = client.Collections.Use("JeopardyQuestion"); + // highlight-start + var groupBy = new GroupByRequest + { + PropertyName = "round", // group by this property + ObjectsPerGroup = 2, // maximum objects per group + NumberOfGroups = 2, // maximum number of groups + }; + + var response = await jeopardy.Query.NearText( + "animals in movies", // find object based on this query + limit: 10, // maximum total objects + returnMetadata: MetadataOptions.Distance, + groupBy: groupBy + ); + // highlight-end + + foreach (var o in response.Objects) + { + Console.WriteLine(o.ID); + Console.WriteLine(o.BelongsToGroup); + Console.WriteLine(o.Metadata.Distance); + } + + foreach (var grp in response.Groups.Values) + { + Console.WriteLine("==========" + grp.Name + "=========="); + Console.WriteLine(grp.Objects); + foreach (var o in grp.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(JsonSerializer.Serialize(o.Metadata)); + } + } + // END GetWithGroupby + + Assert.True(response.Objects.Count() > 0); + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + Assert.True(response.Groups.Count > 0); + Assert.True(response.Groups.Count <= 2); + } + + [Fact] + public async Task GetWithWhere() + { + // ============================ + // ===== QUERY WITH WHERE ===== + // ============================ + + // GetWithWhere + var jeopardy = client.Collections.Use("JeopardyQuestion"); + var response = await jeopardy.Query.NearText( + "animals in movies", + // highlight-start + // TODO[g-despot]: Uncomment when filters becomes available + filter: Filter.Property("round").Equal("Double Jeopardy!"), + // highlight-end + limit: 2, + returnMetadata: MetadataOptions.Distance + ); + + foreach (var o in response.Objects) + { + Console.WriteLine(JsonSerializer.Serialize(o.Properties)); + Console.WriteLine(o.Metadata.Distance); + } + // END GetWithWhere + + Assert.True(response.Objects.Count() > 0); + Assert.Equal("JeopardyQuestion", response.Objects.First().Collection); + Assert.Equal("Double Jeopardy!", response.Objects.First().Properties["round"].ToString()); + Assert.True(response.Objects.First().Properties.ContainsKey("question")); + Assert.NotNull(response.Objects.First().Metadata.Distance); + } +} \ No newline at end of file diff --git a/docs/weaviate/manage-collections/vector-config.mdx b/docs/weaviate/manage-collections/vector-config.mdx index ac9bc5735..172b80b13 100644 --- a/docs/weaviate/manage-collections/vector-config.mdx +++ b/docs/weaviate/manage-collections/vector-config.mdx @@ -13,7 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.collections.t import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.classes_test.go"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/CollectionTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTests.cs"; import VectorConfigSyntax from "/_includes/vector-config-syntax.mdx"; diff --git a/docs/weaviate/manage-objects/create.mdx b/docs/weaviate/manage-objects/create.mdx index 07686f1c4..fde344a81 100644 --- a/docs/weaviate/manage-objects/create.mdx +++ b/docs/weaviate/manage-objects/create.mdx @@ -13,7 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.create.ts"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.create.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsCreateTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.create_test.go"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/ObjectTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageDataTests.cs"; The examples on this page demonstrate how to create individual objects in Weaviate. diff --git a/docs/weaviate/manage-objects/delete.mdx b/docs/weaviate/manage-objects/delete.mdx index bcd29c3c3..45e3cf861 100644 --- a/docs/weaviate/manage-objects/delete.mdx +++ b/docs/weaviate/manage-objects/delete.mdx @@ -13,7 +13,7 @@ import TSCode from "!!raw-loader!/_includes/code/howto/manage-data.delete.ts"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.delete.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsDeleteTest.java"; import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.delete_test.go"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/ObjectTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageDataTests.cs"; import SkipLink from "/src/components/SkipValidationLink"; Weaviate allows object deletion by id or by a set of criteria. diff --git a/docs/weaviate/search/basics.md b/docs/weaviate/search/basics.md index c60b8ad41..dd3ec30ac 100644 --- a/docs/weaviate/search/basics.md +++ b/docs/weaviate/search/basics.md @@ -14,7 +14,7 @@ import TSCode from '!!raw-loader!/\_includes/code/howto/search.basics.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/mainpkg/search-basic_test.go'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/SearchBasicTest.java"; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/search/BasicSearchTest.java'; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchBasicsTests.cs"; With Weaviate you can query your data using [vector similarity search](./similarity.md), [keyword search](./bm25.md), or a mix of both with [hybrid search](./hybrid.md). You can control what object [properties](#specify-object-properties) and [metadata](#retrieve-metadata-values) to return. diff --git a/docs/weaviate/search/similarity.md b/docs/weaviate/search/similarity.md index 3f2153104..7c970bf1e 100644 --- a/docs/weaviate/search/similarity.md +++ b/docs/weaviate/search/similarity.md @@ -14,7 +14,7 @@ import TSCode from '!!raw-loader!/\_includes/code/howto/search.similarity.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/mainpkg/search-similarity_test.go'; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/search/VectorSearchTest.java'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/SearchSimilarityTest.java"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/SearchBasicsTests.cs"; Vector search returns the objects with most similar vectors to that of the query. From b41336afe853cc9e4cd9678bce5a2183232c7771 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:51:12 +0200 Subject: [PATCH 12/18] Update docs and code --- _includes/code/csharp/GetStartedTests.cs | 79 +++++++++++ _includes/code/csharp/HybridSearchTests.cs | 2 +- _includes/code/csharp/KeywordSearchTests.cs | 2 +- _includes/code/csharp/ManageDataTests.cs | 2 +- .../code/csharp/SimilaritySearchTests.cs | 4 +- docs/weaviate/client-libraries/csharp.mdx | 133 ++++++++++++++++++ docs/weaviate/client-libraries/index.mdx | 7 + .../collection-operations.mdx | 16 --- sidebars.js | 5 + versions-config.json | 3 +- 10 files changed, 231 insertions(+), 22 deletions(-) create mode 100644 _includes/code/csharp/GetStartedTests.cs create mode 100644 docs/weaviate/client-libraries/csharp.mdx diff --git a/_includes/code/csharp/GetStartedTests.cs b/_includes/code/csharp/GetStartedTests.cs new file mode 100644 index 000000000..f6e1deb91 --- /dev/null +++ b/_includes/code/csharp/GetStartedTests.cs @@ -0,0 +1,79 @@ +using Xunit; +using Weaviate.Client; +using Weaviate.Client.Models; +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Linq; +using System.Threading.Tasks; +// ... other usings + +// 1. Define your strongly-typed class +public class JeopardyQuestion +{ + public string? question { get; set; } + public string? answer { get; set; } + public string? category { get; set; } +} + +public class GetStartedTests +{ + [Fact] + public async Task GetStarted() + { + var client = Connect.Local(); + const string collectionName = "Question"; + + try + { + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + } + + var questions = await client.Collections.Create(new Collection() + { + Name = collectionName, + VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecOllama()), + Properties = new List + { + Property.Text("answer"), + Property.Text("question"), + Property.Text("category"), + } + }); + + // Download and parse data as before... + using var httpClient = new HttpClient(); + var resp = await httpClient.GetAsync( + "https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json" + ); + resp.EnsureSuccessStatusCode(); + var jsonString = await resp.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(jsonString); + + // ============================= YOUR NEW, CLEAN CODE ============================= + // 2. Prepare the data by mapping it to your new class + var dataObjects = data.Select(d => new JeopardyQuestion + { + answer = d.GetProperty("Answer").GetString(), + question = d.GetProperty("Question").GetString(), + category = d.GetProperty("Category").GetString() + }).ToList(); + // ============================================================================== + + var importResult = await questions.Data.InsertMany(dataObjects); + + var response = await questions.Query.NearText("biology", limit: 2); + // ... rest of the test + Assert.Equal(2, response.Objects.Count()); + } + finally + { + if (await client.Collections.Exists(collectionName)) + { + await client.Collections.Delete(collectionName); + } + } + } +} \ No newline at end of file diff --git a/_includes/code/csharp/HybridSearchTests.cs b/_includes/code/csharp/HybridSearchTests.cs index 030c15f33..bb6ab78b0 100644 --- a/_includes/code/csharp/HybridSearchTests.cs +++ b/_includes/code/csharp/HybridSearchTests.cs @@ -344,7 +344,7 @@ public async Task HybridWithVector() var response = await jeopardy.Query.Hybrid( "food", // highlight-start - vectors: VectorData.Create("default", queryVector), + vectors: Vectors.Create("default", queryVector), // highlight-end alpha: 0.25f, limit: 3 diff --git a/_includes/code/csharp/KeywordSearchTests.cs b/_includes/code/csharp/KeywordSearchTests.cs index f14daefbe..8dfbf282a 100644 --- a/_includes/code/csharp/KeywordSearchTests.cs +++ b/_includes/code/csharp/KeywordSearchTests.cs @@ -242,7 +242,7 @@ public async Task BM25WithFilter() var response = await jeopardy.Query.BM25( "food", // highlight-start - filter: Filter.Property("round").Equal("Double Jeopardy!"), + filters: Filter.Property("round").Equal("Double Jeopardy!"), // highlight-end returnProperties: new[] { "answer", "question", "round" }, // return these properties limit: 3 diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageDataTests.cs index 98b8783b5..882f52c0e 100644 --- a/_includes/code/csharp/ManageDataTests.cs +++ b/_includes/code/csharp/ManageDataTests.cs @@ -252,7 +252,7 @@ await publications.Data.Insert( // END WithGeoCoordinates var response = await publications.Query.FetchObjects( - filter: Filter.Property("headquartersGeoLocation") + filters: Filter.Property("headquartersGeoLocation") .WithinGeoRange( new GeoCoordinateConstraint(52.39f, 4.84f, 1000) ) diff --git a/_includes/code/csharp/SimilaritySearchTests.cs b/_includes/code/csharp/SimilaritySearchTests.cs index 7a2062f68..a4ba995f2 100644 --- a/_includes/code/csharp/SimilaritySearchTests.cs +++ b/_includes/code/csharp/SimilaritySearchTests.cs @@ -156,7 +156,7 @@ public async Task GetNearVector() // GetNearVector // highlight-start var response = await jeopardy.Query.NearVector( - VectorData.Create("default", queryVector), // your query vector goes here + Vectors.Create(("default", queryVector)), // your query vector goes here // highlight-end limit: 2, returnMetadata: MetadataOptions.Distance @@ -310,7 +310,7 @@ public async Task GetWithWhere() "animals in movies", // highlight-start // TODO[g-despot]: Uncomment when filters becomes available - filter: Filter.Property("round").Equal("Double Jeopardy!"), + filters: Filter.Property("round").Equal("Double Jeopardy!"), // highlight-end limit: 2, returnMetadata: MetadataOptions.Distance diff --git a/docs/weaviate/client-libraries/csharp.mdx b/docs/weaviate/client-libraries/csharp.mdx new file mode 100644 index 000000000..ec9838525 --- /dev/null +++ b/docs/weaviate/client-libraries/csharp.mdx @@ -0,0 +1,133 @@ +--- +title: C# - Beta release +sidebar_label: C# 🚧 +description: "Official C# client library documentation for integrating Weaviate with .NET applications and services." +image: og/docs/client-libraries.jpg +# tags: ['c#', 'csharp', 'client library', 'experimental'] +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/GetStartedTests.cs"; +import QuickLinks from "/src/components/QuickLinks"; + +:::caution Preview + +The `C#` client is available as a beta release.
+ +This means that the library is still under development and may change in future releases, including potential breaking changes. +**We do not recommend using this client library in production environments at this time.** + +::: + +export const csharpCardsData = [ + { + title: "weaviate/csharp-client", + link: "https://github.com/weaviate/csharp-client/tree/mvp", + icon: "fa-brands fa-github", + }, + /*{ + title: "Reference manual", + link: "https://javadoc.io/doc/io.weaviate/client/latest/index.html", + icon: "fa-solid fa-book", + },*/ +]; + +:::note C# client (SDK) + +The latest C# client is version `v||site.csharp_client_version||`. + + + +::: + +This page broadly covers the Weaviate C# (beta release). For usage information not specific to the C# client, such as code examples, see the relevant pages in the [How-to manuals & Guides](../../guides.mdx). + +## Installation + +```xml + +``` + +
+ Requirements: Weaviate version compatibility & gRPC + +#### Weaviate version compatibility + +The C# client requires Weaviate `1.33.0` or higher. Generally, we encourage you to use the latest version of the C# client and the Weaviate Database. + +#### gRPC + +The C# client uses remote procedure calls (RPCs) under-the-hood. Accordingly, a port for gRPC must be open to your Weaviate server. + +
+ docker-compose.yml example + +If you are running Weaviate with Docker, you can map the default port (`50051`) by adding the following to your `docker-compose.yml` file: + +```yaml +ports: + - 8080:8080 + - 50051:50051 +``` + +
+
+ +## Get started + +import BasicPrereqs from "/_includes/prerequisites-quickstart.md"; + + + +Get started with Weaviate using this C# example. The code walks you through these key steps: + +1. **[Connect to Weaviate](docs/weaviate/connections/index.mdx)**: Establish a connection to a local (or Cloud) Weaviate instance. +1. **[Create a collection](../../manage-collections/index.mdx)**: Define the data schema for a `Question` collection, using an Ollama model to vectorize the data. +1. **[Import data](../../manage-objects/import.mdx)**: Fetch sample Jeopardy questions and use Weaviate's batch import for efficient ingestion and automatic vector embedding generation. +1. **[Search/query the database](../../search/index.mdx)**: Execute a vector search to find questions semantically similar to the query `biology`. + + + + + + + +For more code examples, check out the [How-to manuals & Guides](../../guides.mdx) section. + +## Asynchronous usage + +_Coming soon_ + + + +## Releases + +Go to the [GitHub releases page](https://github.com/weaviate/csharp-client/releases) to see the history of the C# client library releases and change logs. + +
+ Click here for a table of Weaviate and corresponding client versions + +import ReleaseHistory from "/_includes/release-history.md"; + + + +
+ +## Code examples & further resources + +import CodeExamples from "/_includes/clients/code-examples.mdx"; + + + +## Questions and feedback + +import DocsFeedback from "/_includes/docs-feedback.mdx"; + + diff --git a/docs/weaviate/client-libraries/index.mdx b/docs/weaviate/client-libraries/index.mdx index 5c445cd23..001d44e6d 100644 --- a/docs/weaviate/client-libraries/index.mdx +++ b/docs/weaviate/client-libraries/index.mdx @@ -47,6 +47,13 @@ export const clientLibrariesData = [ link: "/weaviate/client-libraries/java", icon: "fab fa-java", }, + { + title: "C# Client", + description: + "Install and use the official C# library for interacting with Weaviate.", + link: "/weaviate/client-libraries/java", + icon: "fab fa-microsoft", + }, ];
diff --git a/docs/weaviate/manage-collections/collection-operations.mdx b/docs/weaviate/manage-collections/collection-operations.mdx index f6189f3ee..da6be59ab 100644 --- a/docs/weaviate/manage-collections/collection-operations.mdx +++ b/docs/weaviate/manage-collections/collection-operations.mdx @@ -639,14 +639,6 @@ We are working on a re-indexing API to allow you to re-index the data after addi language="py" /> - - - - - - Date: Thu, 2 Oct 2025 13:37:35 +0200 Subject: [PATCH 13/18] Update docs --- _includes/code/csharp/ManageDataTests.cs | 4 +- _includes/schema-delete-class.mdx | 2 +- docs/weaviate/client-libraries/csharp.mdx | 10 +- docs/weaviate/connections/connect-cloud.mdx | 2 +- docs/weaviate/connections/connect-custom.mdx | 2 +- docs/weaviate/connections/connect-local.mdx | 6 +- .../collection-operations.mdx | 22 +- .../manage-collections/vector-config.mdx | 2 +- docs/weaviate/manage-objects/create.mdx | 6 +- docs/weaviate/manage-objects/delete.mdx | 2 +- docs/weaviate/search/basics.md | 2 +- docs/weaviate/search/similarity.md | 2 +- sidebars.js | 1 + tools/add_csharp.py | 209 ++++++++++++++++++ 14 files changed, 241 insertions(+), 31 deletions(-) create mode 100644 tools/add_csharp.py diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageDataTests.cs index 882f52c0e..2e83f0def 100644 --- a/_includes/code/csharp/ManageDataTests.cs +++ b/_includes/code/csharp/ManageDataTests.cs @@ -103,7 +103,7 @@ public async Task DisposeAsync() [Fact] public async Task CreateObject() { - // CreateObject START + // START CreateSimpleObject var jeopardy = weaviate.Collections.Use("JeopardyQuestion"); // highlight-start @@ -116,7 +116,7 @@ public async Task CreateObject() }); Console.WriteLine(uuid); // the return value is the object's UUID - // CreateObject END + // END CreateSimpleObject // Test var result = await jeopardy.Query.FetchObjectByID(uuid); diff --git a/_includes/schema-delete-class.mdx b/_includes/schema-delete-class.mdx index cf35d6c12..348f2d40c 100644 --- a/_includes/schema-delete-class.mdx +++ b/_includes/schema-delete-class.mdx @@ -90,7 +90,7 @@ curl \ ``` - + @@ -99,7 +99,7 @@ Get started with Weaviate using this C# example. The code walks you through thes -For more code examples, check out the [How-to manuals & Guides](../../guides.mdx) section. +For more code examples, check out the [How-to manuals & Guides](../guides.mdx) section. ## Asynchronous usage diff --git a/docs/weaviate/connections/connect-cloud.mdx b/docs/weaviate/connections/connect-cloud.mdx index b39d3fc3e..7cd0f70d2 100644 --- a/docs/weaviate/connections/connect-cloud.mdx +++ b/docs/weaviate/connections/connect-cloud.mdx @@ -102,7 +102,7 @@ import HostnameWarning from "/_includes/wcs/hostname-warning.mdx"; /> - + - + - + - + - + @@ -75,7 +75,7 @@ import InitialCaps from "/_includes/schemas/initial-capitalization.md"; language="java" /> - + - + - + - + - + - + - + - + - + diff --git a/docs/weaviate/manage-objects/delete.mdx b/docs/weaviate/manage-objects/delete.mdx index 45e3cf861..cbad09fe1 100644 --- a/docs/weaviate/manage-objects/delete.mdx +++ b/docs/weaviate/manage-objects/delete.mdx @@ -77,7 +77,7 @@ To delete by id, specify the collection name and the object id. language="java" /> - + - + - + + + """ + + +def process_imports(content): + """ + Adds a CSharpCode import if a JavaV6Code import exists and the CSharpCode + import does not. + """ + # If C# import already exists, do nothing. + if re.search(r"import\s+CSharpCode\s+from", content): + return content + + # Find the Java V6 import to base the new import on. + # It captures the full import statement and the file path part. + java_import_match = re.search( + r'(import\s+JavaV6Code\s+from\s+([\'"]).*?java-v6/(.*?)(\2;))', + content, + re.DOTALL, + ) + if not java_import_match: + return content + + full_import_statement = java_import_match.group(0) + java_file_path = java_import_match.group(3) + + # Create the corresponding C# file path by replacing .java with .cs + csharp_file_path = re.sub(r"\.java$", ".cs", java_file_path) + + # Create the new import statement for C# + new_import_statement = ( + full_import_statement.replace("JavaV6Code", "CSharpCode") + .replace("java-v6/", "csharp/") + .replace(java_file_path, csharp_file_path) + ) + + # Insert the new import directly after the Java V6 one for consistency. + return content.replace( + full_import_statement, f"{full_import_statement}\n{new_import_statement}" + ) + + +def add_csharp_tab_to_block(tabs_block_match): + """ + A replacer function for re.sub that processes a single ... block. + """ + tabs_block = tabs_block_match.group(0) + + # Condition 1: Don't add if a C# tab already exists. + # Condition 2: Don't add if there's no Java v6 tab to use as a template. + if 'value="csharp"' in tabs_block or 'value="java6"' not in tabs_block: + return tabs_block + + # Find the Java v6 tab. We assume TabItems are not nested within each other. + java6_tab_match = re.search( + r'(.*?)', tabs_block, re.DOTALL + ) + if not java6_tab_match: + return tabs_block + + java6_tab_text = java6_tab_match.group(1) + + # Extract start and end markers from within the Java v6 tab text. + marker_match = re.search( + r'startMarker="([^"]+)"[\s\S]*?endMarker="([^"]+)"', java6_tab_text, re.DOTALL + ) + if not marker_match: + # Cannot proceed if markers aren't found in the Java v6 tab. + return tabs_block + + start_marker, end_marker = marker_match.groups() + + # Create the new C# tab from the template. + csharp_tab_text = CSHARP_TAB_TEMPLATE.format( + start_marker=start_marker, end_marker=end_marker + ).strip() + + # Determine the correct insertion point. + # We insert after the Java v6 tab, OR after the regular Java tab + # if it immediately follows the Java v6 tab. + + end_of_java6_match = java6_tab_match.end() + rest_of_block_after_java6 = tabs_block[end_of_java6_match:] + + # Check if the next element is a regular Java tab. + if re.match(r'\s*.*?)', + rest_of_block_after_java6, + re.DOTALL, + ) + if java_tab_match: + java_tab_text = java_tab_match.group(1) + # Replace the Java tab with itself plus the new C# tab. + return tabs_block.replace( + java_tab_text, f"{java_tab_text}\n {csharp_tab_text}" + ) + + # If no regular Java tab followed, insert after the Java v6 tab. + # Replace the Java v6 tab with itself plus the new C# tab. + return tabs_block.replace(java6_tab_text, f"{java6_tab_text}\n {csharp_tab_text}") + + +def process_file_content(content): + """ + Runs the import and tab processing on the entire file content. + Returns the new content and a boolean indicating if changes were made. + """ + original_content = content + + # Step 1: Add C# import statement if needed. + content_with_imports = process_imports(original_content) + + # Step 2: Find all blocks and apply the replacer function to each. + tabs_pattern = re.compile(r"]*>.*?", re.DOTALL) + new_content = tabs_pattern.sub(add_csharp_tab_to_block, content_with_imports) + + return new_content, new_content != original_content + + +def process_directory(directory_path, file_extensions, dry_run=True): + """ + Process all files with given extensions in a directory and its subdirectories. + """ + directory = Path(directory_path) + files_processed = 0 + files_modified = 0 + + for ext in file_extensions: + for file_path in directory.glob(f"**/*{ext}"): + files_processed += 1 + + # Read the file content + with open(file_path, "r", encoding="utf-8") as file: + try: + content = file.read() + except UnicodeDecodeError: + print(f"Error reading {file_path}: UnicodeDecodeError") + continue + + # Process the content to add tabs and imports + new_content, was_modified = process_file_content(content) + + # If content was modified + if was_modified: + files_modified += 1 + print(f"Modified: {file_path}") + + # Write the changes if not in dry-run mode + if not dry_run: + with open(file_path, "w", encoding="utf-8") as file: + file.write(new_content) + + return files_processed, files_modified + + +def main(): + parser = argparse.ArgumentParser( + description="Adds C# TabItem blocks after Java v6/Java tabs in documentation files." + ) + parser.add_argument("directory", help="Directory to process") + parser.add_argument( + "--ext", + nargs="+", + default=[".md", ".mdx"], + help="File extensions to process (default: .md .mdx)", + ) + parser.add_argument( + "--apply", + action="store_true", + help="Apply changes (without this flag, runs in dry-run mode)", + ) + + args = parser.parse_args() + + print(f"Processing files in {args.directory}") + print(f"File extensions: {', '.join(args.ext)}") + print( + f"Mode: {'Apply Changes' if args.apply else 'Dry Run (no changes will be made)'}" + ) + + files_processed, files_modified = process_directory( + args.directory, args.ext, dry_run=not args.apply + ) + + print(f"\nSummary:") + print(f"Files processed: {files_processed}") + print(f"Files that would be/were modified: {files_modified}") + + if not args.apply and files_modified > 0: + print("\nRun with --apply to make the changes.") + + +if __name__ == "__main__": + main() From 1195591d94fb5e447208edf9c0f1c87c5145b0b6 Mon Sep 17 00:00:00 2001 From: Ivan Despot <66276597+g-despot@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:59:21 +0200 Subject: [PATCH 14/18] Rebase with Java v6 docs --- .../code/connections/timeouts-custom.mdx | 9 ++ _includes/code/connections/timeouts-local.mdx | 9 ++ _includes/code/csharp/ConfigureBQTest.cs | 0 _includes/code/csharp/ConfigurePQTest.cs | 0 _includes/code/csharp/ConfigureRQTest.cs | 0 _includes/code/csharp/ConfigureSQTest.cs | 0 .../{ConnectionTests.cs => ConnectionTest.cs} | 0 .../{GetStartedTests.cs => GetStartedTest.cs} | 0 .../code/csharp/ManageCollectionsAliasTest.cs | 0 .../ManageCollectionsCrossReferencesTest.cs | 0 .../ManageCollectionsMigrateDataTest.cs | 0 ...tionsTests.cs => ManageCollectionsTest.cs} | 0 ...ataTests.cs => ManageObjectsCreateTest.cs} | 0 .../code/csharp/ManageObjectsDeleteTest.cs | 0 ...ortTests.cs => ManageObjectsImportTest.cs} | 0 .../code/csharp/ManageObjectsReadAllTest.cs | 0 .../code/csharp/ManageObjectsReadTest.cs | 0 .../code/csharp/ManageObjectsUpdateTest.cs | 0 _includes/code/csharp/ModelProvidersTest.cs | 0 _includes/code/csharp/QuickstartLocalTest.cs | 0 _includes/code/csharp/QuickstartTest.cs | 0 _includes/code/csharp/SearchAggregateTest.cs | 0 ...earchBasicsTests.cs => SearchBasicTest.cs} | 0 _includes/code/csharp/SearchFiltersTest.cs | 0 ...bridSearchTests.cs => SearchHybridTest.cs} | 0 ...ImageSearchTests.cs => SearchImageTest.cs} | 0 ...ordSearchTests.cs => SearchKeywordTest.cs} | 0 ...SearchTests.cs => SearchSimilarityTest.cs} | 0 .../csharp/StarterGuidesCollectionsTest.cs | 0 .../csharp/StarterGuidesCustomVectorsTest.cs | 0 .../_ManageCollectionsMultiTenancyTest.cs | 0 .../code/csharp/_SearchGenerativeTest.cs | 0 .../code/csharp/_SearchMultiTargetTest.cs | 0 .../howto/manage-data.create.with.geo.mdx | 9 ++ .../manage-data.read.check.existence.mdx | 9 ++ .../code/howto/manage-data.shards.inspect.mdx | 9 ++ .../code/howto/manage-data.shards.update.mdx | 9 ++ _includes/code/quickstart.byov.schema.mdx | 35 +++-- ...uickstart.import.questions-and-vectors.mdx | 9 ++ _includes/code/quickstart/connect.partial.mdx | 9 ++ .../local.quickstart.create_collection.mdx | 9 ++ .../local.quickstart.import_objects.mdx | 9 ++ .../quickstart/local.quickstart.is_ready.mdx | 9 ++ .../local.quickstart.query.neartext.mdx | 9 ++ .../quickstart/local.quickstart.query.rag.mdx | 9 ++ .../quickstart.create_collection.mdx | 9 ++ .../quickstart/quickstart.import_objects.mdx | 9 ++ .../code/quickstart/quickstart.is_ready.mdx | 9 ++ .../quickstart/quickstart.query.neartext.mdx | 9 ++ .../code/quickstart/quickstart.query.rag.mdx | 9 ++ .../code/replication.get.object.by.id.mdx | 9 ++ .../code/schema.things.properties.add.mdx | 9 ++ _includes/code/tutorial.schema.create.mdx | 17 ++- .../code/tutorial.schema.index-settings.mdx | 9 ++ .../code/tutorial.schema.multi-tenancy.mdx | 9 ++ .../tutorial.schema.properties.options.mdx | 9 ++ _includes/schema-delete-class.mdx | 2 +- ...viate-embeddings-vectorizer-parameters.mdx | 76 ++++++----- docs/weaviate/client-libraries/csharp.mdx | 2 +- .../compression/bq-compression.md | 25 ++++ .../compression/pq-compression.md | 33 +++++ .../compression/rq-compression.md | 40 ++++++ .../compression/sq-compression.md | 25 ++++ .../configuration/compression/uncompressed.md | 9 ++ docs/weaviate/connections/connect-cloud.mdx | 10 +- docs/weaviate/connections/connect-custom.mdx | 10 +- docs/weaviate/connections/connect-local.mdx | 10 +- .../manage-collections/collection-aliases.mdx | 57 ++++++++ .../collection-operations.mdx | 2 +- .../manage-collections/cross-references.mdx | 97 +++++++++++++ .../generative-reranker-models.mdx | 33 +++++ .../manage-collections/inverted-index.mdx | 25 ++++ docs/weaviate/manage-collections/migrate.mdx | 81 +++++++++++ .../manage-collections/multi-node-setup.mdx | 17 +++ .../manage-collections/multi-tenancy.mdx | 65 +++++++++ .../manage-collections/tenant-states.mdx | 33 +++++ .../manage-collections/vector-config.mdx | 66 ++++++++- docs/weaviate/manage-objects/create.mdx | 50 ++++++- docs/weaviate/manage-objects/delete.mdx | 34 ++++- docs/weaviate/manage-objects/import.mdx | 81 +++++++++++ .../manage-objects/read-all-objects.mdx | 25 ++++ docs/weaviate/manage-objects/read.mdx | 25 ++++ docs/weaviate/manage-objects/update.mdx | 33 +++++ .../model-providers/weaviate/embeddings.md | 49 +++++++ docs/weaviate/search/aggregate.md | 65 +++++++++ docs/weaviate/search/basics.md | 74 +++++++++- docs/weaviate/search/bm25.md | 97 +++++++++++++ docs/weaviate/search/filters.md | 121 ++++++++++++++++ docs/weaviate/search/hybrid.md | 129 ++++++++++++++++++ docs/weaviate/search/image.md | 25 ++++ docs/weaviate/search/similarity.md | 74 +++++++++- .../starter-guides/custom-vectors.mdx | 9 ++ .../weaviate/tutorials/collection-aliases.mdx | 65 +++++++++ 93 files changed, 1871 insertions(+), 62 deletions(-) create mode 100644 _includes/code/csharp/ConfigureBQTest.cs create mode 100644 _includes/code/csharp/ConfigurePQTest.cs create mode 100644 _includes/code/csharp/ConfigureRQTest.cs create mode 100644 _includes/code/csharp/ConfigureSQTest.cs rename _includes/code/csharp/{ConnectionTests.cs => ConnectionTest.cs} (100%) rename _includes/code/csharp/{GetStartedTests.cs => GetStartedTest.cs} (100%) create mode 100644 _includes/code/csharp/ManageCollectionsAliasTest.cs create mode 100644 _includes/code/csharp/ManageCollectionsCrossReferencesTest.cs create mode 100644 _includes/code/csharp/ManageCollectionsMigrateDataTest.cs rename _includes/code/csharp/{ManageCollectionsTests.cs => ManageCollectionsTest.cs} (100%) rename _includes/code/csharp/{ManageDataTests.cs => ManageObjectsCreateTest.cs} (100%) create mode 100644 _includes/code/csharp/ManageObjectsDeleteTest.cs rename _includes/code/csharp/{BatchImportTests.cs => ManageObjectsImportTest.cs} (100%) create mode 100644 _includes/code/csharp/ManageObjectsReadAllTest.cs create mode 100644 _includes/code/csharp/ManageObjectsReadTest.cs create mode 100644 _includes/code/csharp/ManageObjectsUpdateTest.cs create mode 100644 _includes/code/csharp/ModelProvidersTest.cs create mode 100644 _includes/code/csharp/QuickstartLocalTest.cs create mode 100644 _includes/code/csharp/QuickstartTest.cs create mode 100644 _includes/code/csharp/SearchAggregateTest.cs rename _includes/code/csharp/{SearchBasicsTests.cs => SearchBasicTest.cs} (100%) create mode 100644 _includes/code/csharp/SearchFiltersTest.cs rename _includes/code/csharp/{HybridSearchTests.cs => SearchHybridTest.cs} (100%) rename _includes/code/csharp/{ImageSearchTests.cs => SearchImageTest.cs} (100%) rename _includes/code/csharp/{KeywordSearchTests.cs => SearchKeywordTest.cs} (100%) rename _includes/code/csharp/{SimilaritySearchTests.cs => SearchSimilarityTest.cs} (100%) create mode 100644 _includes/code/csharp/StarterGuidesCollectionsTest.cs create mode 100644 _includes/code/csharp/StarterGuidesCustomVectorsTest.cs create mode 100644 _includes/code/csharp/_ManageCollectionsMultiTenancyTest.cs create mode 100644 _includes/code/csharp/_SearchGenerativeTest.cs create mode 100644 _includes/code/csharp/_SearchMultiTargetTest.cs diff --git a/_includes/code/connections/timeouts-custom.mdx b/_includes/code/connections/timeouts-custom.mdx index a51bf15fc..c16868653 100644 --- a/_includes/code/connections/timeouts-custom.mdx +++ b/_includes/code/connections/timeouts-custom.mdx @@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl import PyV4Code from "!!raw-loader!/_includes/code/connections/connect-python-v4.py"; import TsV3Code from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ConnectionTest.cs"; @@ -31,4 +32,12 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Conne language="java" /> + + + diff --git a/_includes/code/connections/timeouts-local.mdx b/_includes/code/connections/timeouts-local.mdx index d17480b8e..3fdf82267 100644 --- a/_includes/code/connections/timeouts-local.mdx +++ b/_includes/code/connections/timeouts-local.mdx @@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl import PyV4Code from "!!raw-loader!/_includes/code/connections/connect-python-v4.py"; import TsV3Code from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ConnectionTest.cs"; @@ -31,4 +32,12 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Conne language="java" /> + + + diff --git a/_includes/code/csharp/ConfigureBQTest.cs b/_includes/code/csharp/ConfigureBQTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ConfigurePQTest.cs b/_includes/code/csharp/ConfigurePQTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ConfigureRQTest.cs b/_includes/code/csharp/ConfigureRQTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ConfigureSQTest.cs b/_includes/code/csharp/ConfigureSQTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ConnectionTests.cs b/_includes/code/csharp/ConnectionTest.cs similarity index 100% rename from _includes/code/csharp/ConnectionTests.cs rename to _includes/code/csharp/ConnectionTest.cs diff --git a/_includes/code/csharp/GetStartedTests.cs b/_includes/code/csharp/GetStartedTest.cs similarity index 100% rename from _includes/code/csharp/GetStartedTests.cs rename to _includes/code/csharp/GetStartedTest.cs diff --git a/_includes/code/csharp/ManageCollectionsAliasTest.cs b/_includes/code/csharp/ManageCollectionsAliasTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ManageCollectionsCrossReferencesTest.cs b/_includes/code/csharp/ManageCollectionsCrossReferencesTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ManageCollectionsMigrateDataTest.cs b/_includes/code/csharp/ManageCollectionsMigrateDataTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ManageCollectionsTests.cs b/_includes/code/csharp/ManageCollectionsTest.cs similarity index 100% rename from _includes/code/csharp/ManageCollectionsTests.cs rename to _includes/code/csharp/ManageCollectionsTest.cs diff --git a/_includes/code/csharp/ManageDataTests.cs b/_includes/code/csharp/ManageObjectsCreateTest.cs similarity index 100% rename from _includes/code/csharp/ManageDataTests.cs rename to _includes/code/csharp/ManageObjectsCreateTest.cs diff --git a/_includes/code/csharp/ManageObjectsDeleteTest.cs b/_includes/code/csharp/ManageObjectsDeleteTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/BatchImportTests.cs b/_includes/code/csharp/ManageObjectsImportTest.cs similarity index 100% rename from _includes/code/csharp/BatchImportTests.cs rename to _includes/code/csharp/ManageObjectsImportTest.cs diff --git a/_includes/code/csharp/ManageObjectsReadAllTest.cs b/_includes/code/csharp/ManageObjectsReadAllTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ManageObjectsReadTest.cs b/_includes/code/csharp/ManageObjectsReadTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ManageObjectsUpdateTest.cs b/_includes/code/csharp/ManageObjectsUpdateTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/ModelProvidersTest.cs b/_includes/code/csharp/ModelProvidersTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/QuickstartLocalTest.cs b/_includes/code/csharp/QuickstartLocalTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/QuickstartTest.cs b/_includes/code/csharp/QuickstartTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/SearchAggregateTest.cs b/_includes/code/csharp/SearchAggregateTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/SearchBasicsTests.cs b/_includes/code/csharp/SearchBasicTest.cs similarity index 100% rename from _includes/code/csharp/SearchBasicsTests.cs rename to _includes/code/csharp/SearchBasicTest.cs diff --git a/_includes/code/csharp/SearchFiltersTest.cs b/_includes/code/csharp/SearchFiltersTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/HybridSearchTests.cs b/_includes/code/csharp/SearchHybridTest.cs similarity index 100% rename from _includes/code/csharp/HybridSearchTests.cs rename to _includes/code/csharp/SearchHybridTest.cs diff --git a/_includes/code/csharp/ImageSearchTests.cs b/_includes/code/csharp/SearchImageTest.cs similarity index 100% rename from _includes/code/csharp/ImageSearchTests.cs rename to _includes/code/csharp/SearchImageTest.cs diff --git a/_includes/code/csharp/KeywordSearchTests.cs b/_includes/code/csharp/SearchKeywordTest.cs similarity index 100% rename from _includes/code/csharp/KeywordSearchTests.cs rename to _includes/code/csharp/SearchKeywordTest.cs diff --git a/_includes/code/csharp/SimilaritySearchTests.cs b/_includes/code/csharp/SearchSimilarityTest.cs similarity index 100% rename from _includes/code/csharp/SimilaritySearchTests.cs rename to _includes/code/csharp/SearchSimilarityTest.cs diff --git a/_includes/code/csharp/StarterGuidesCollectionsTest.cs b/_includes/code/csharp/StarterGuidesCollectionsTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/StarterGuidesCustomVectorsTest.cs b/_includes/code/csharp/StarterGuidesCustomVectorsTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/_ManageCollectionsMultiTenancyTest.cs b/_includes/code/csharp/_ManageCollectionsMultiTenancyTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/_SearchGenerativeTest.cs b/_includes/code/csharp/_SearchGenerativeTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/csharp/_SearchMultiTargetTest.cs b/_includes/code/csharp/_SearchMultiTargetTest.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_includes/code/howto/manage-data.create.with.geo.mdx b/_includes/code/howto/manage-data.create.with.geo.mdx index a837362a6..5bb29338f 100644 --- a/_includes/code/howto/manage-data.create.with.geo.mdx +++ b/_includes/code/howto/manage-data.create.with.geo.mdx @@ -3,6 +3,7 @@ import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; import PyCode from '!!raw-loader!/_includes/code/howto/manage-data.create.py'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsCreateTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageObjectsCreateTest.cs"; @@ -126,4 +127,12 @@ public class App { language="java" /> + + + diff --git a/_includes/code/howto/manage-data.read.check.existence.mdx b/_includes/code/howto/manage-data.read.check.existence.mdx index ec4c872b0..6c7a8d971 100644 --- a/_includes/code/howto/manage-data.read.check.existence.mdx +++ b/_includes/code/howto/manage-data.read.check.existence.mdx @@ -3,6 +3,7 @@ import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; import PyCode from '!!raw-loader!/_includes/code/howto/manage-data.create.py'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageObjectsReadTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageObjectsReadTest.cs"; @@ -129,5 +130,13 @@ public class App { ``` + + + diff --git a/_includes/code/howto/manage-data.shards.inspect.mdx b/_includes/code/howto/manage-data.shards.inspect.mdx index 3b8fe1c43..f387f8212 100644 --- a/_includes/code/howto/manage-data.shards.inspect.mdx +++ b/_includes/code/howto/manage-data.shards.inspect.mdx @@ -5,6 +5,7 @@ import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBl import PyCode from '!!raw-loader!/_includes/code/howto/manage-data.collections.py'; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTest.cs"; @@ -77,4 +78,12 @@ func main() { language="java" /> + + + diff --git a/_includes/code/howto/manage-data.shards.update.mdx b/_includes/code/howto/manage-data.shards.update.mdx index 048158e9b..79f09f2bd 100644 --- a/_includes/code/howto/manage-data.shards.update.mdx +++ b/_includes/code/howto/manage-data.shards.update.mdx @@ -6,6 +6,7 @@ import PyCode from "!!raw-loader!/_includes/code/howto/manage-data.collections.p import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/manage-data.shards_test.go"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTest.cs"; @@ -53,4 +54,12 @@ console.log(JSON.stringify(shards, null, 2)); language="java" /> + + + diff --git a/_includes/code/quickstart.byov.schema.mdx b/_includes/code/quickstart.byov.schema.mdx index 618567a93..aca689617 100644 --- a/_includes/code/quickstart.byov.schema.mdx +++ b/_includes/code/quickstart.byov.schema.mdx @@ -1,12 +1,13 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import ByovAllPyCode from '!!raw-loader!/_includes/code/quickstart.byov.all.py'; -import ByovAllTsCode from '!!raw-loader!/_includes/code/quickstart.byov.all.ts'; -import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/StarterGuidesCustomVectorsTest.java"; -import ByovAllShCode from '!!raw-loader!/_includes/code/quickstart.byov.all.sh'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; +import ByovAllPyCode from "!!raw-loader!/_includes/code/quickstart.byov.all.py"; +import ByovAllTsCode from "!!raw-loader!/_includes/code/quickstart.byov.all.ts"; +import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/StarterGuidesCustomVectorsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/StarterGuidesCustomVectorsTest.cs"; +import ByovAllShCode from "!!raw-loader!/_includes/code/quickstart.byov.all.sh"; @@ -18,12 +19,12 @@ import ByovAllShCode from '!!raw-loader!/_includes/code/quickstart.byov.all.sh'; /> - + + + + @@ -32,4 +33,12 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Start language="java" /> + + + diff --git a/_includes/code/quickstart/connect.partial.mdx b/_includes/code/quickstart/connect.partial.mdx index 34664e533..b196e3b21 100644 --- a/_includes/code/quickstart/connect.partial.mdx +++ b/_includes/code/quickstart/connect.partial.mdx @@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl import PyCodeV4 from "!!raw-loader!/_includes/code/connections/connect-python-v4.py"; import TsCodeV3 from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ConnectionTest.cs"; import JavaCode from "!!raw-loader!/_includes/code/connections/connect.java"; import ShellCode from "!!raw-loader!/_includes/code/connections/connect.sh"; import GoCode from "!!raw-loader!/_includes/code/connections/connect.go"; @@ -56,6 +57,14 @@ import HostnameWarning from "/_includes/wcs/hostname-warning.mdx"; /> + + + + + + diff --git a/_includes/code/quickstart/local.quickstart.import_objects.mdx b/_includes/code/quickstart/local.quickstart.import_objects.mdx index 226613983..3e0161444 100644 --- a/_includes/code/quickstart/local.quickstart.import_objects.mdx +++ b/_includes/code/quickstart/local.quickstart.import_objects.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/local.quickstart.import_ import TSCode from '!!raw-loader!/_includes/code/typescript/local.quickstart.import_objects.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart_local/2_2_add_objects/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartLocalTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartLocalTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart_local/Import.java'; @@ -63,6 +64,14 @@ During a batch import, any failed objects can be obtained through `batch.failed_ title="quickstart/Import.java" /> + + + diff --git a/_includes/code/quickstart/local.quickstart.is_ready.mdx b/_includes/code/quickstart/local.quickstart.is_ready.mdx index 1bea7c0d2..5ddd88578 100644 --- a/_includes/code/quickstart/local.quickstart.is_ready.mdx +++ b/_includes/code/quickstart/local.quickstart.is_ready.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/local.quickstart.is_read import TSCode from '!!raw-loader!/_includes/code/typescript/local.quickstart.is_ready.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart_local/1_is_ready/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartLocalTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartLocalTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart_local/IsReady.java'; @@ -61,6 +62,14 @@ import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/w title="quickstart/IsReady.java" /> + + + diff --git a/_includes/code/quickstart/local.quickstart.query.neartext.mdx b/_includes/code/quickstart/local.quickstart.query.neartext.mdx index d743019c3..ba02d5453 100644 --- a/_includes/code/quickstart/local.quickstart.query.neartext.mdx +++ b/_includes/code/quickstart/local.quickstart.query.neartext.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/local.quickstart.query.n import TSCode from '!!raw-loader!/_includes/code/typescript/local.quickstart.query.neartext.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart_local/3_1_neartext/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartLocalTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartLocalTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart_local/NearText.java'; @@ -61,6 +62,14 @@ import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/w title="quickstart/NearText.java" /> + + + diff --git a/_includes/code/quickstart/local.quickstart.query.rag.mdx b/_includes/code/quickstart/local.quickstart.query.rag.mdx index e1f723088..4d8fb0971 100644 --- a/_includes/code/quickstart/local.quickstart.query.rag.mdx +++ b/_includes/code/quickstart/local.quickstart.query.rag.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/local.quickstart.query.r import TSCode from '!!raw-loader!/_includes/code/typescript/local.quickstart.query.rag.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart_local/3_2_rag/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartLocalTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartLocalTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart_local/RAG.java'; @@ -61,6 +62,14 @@ import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/w title="quickstart/RAG.java" /> + + + diff --git a/_includes/code/quickstart/quickstart.create_collection.mdx b/_includes/code/quickstart/quickstart.create_collection.mdx index c8ce52004..1b9a139fb 100644 --- a/_includes/code/quickstart/quickstart.create_collection.mdx +++ b/_includes/code/quickstart/quickstart.create_collection.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/quickstart.create_collec import TSCode from '!!raw-loader!/_includes/code/typescript/quickstart.create_collection.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart/2_1_create_collection/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart/CreateCollection.java'; import VectorConfigSyntax from "/_includes/vector-config-syntax.mdx"; import VectorsAutoSchemaError from "/_includes/error-note-vectors-autoschema.mdx"; @@ -67,6 +68,14 @@ import VectorsAutoSchemaError from "/_includes/error-note-vectors-autoschema.mdx /> + + + diff --git a/_includes/code/quickstart/quickstart.import_objects.mdx b/_includes/code/quickstart/quickstart.import_objects.mdx index b10076518..b74e0c1a3 100644 --- a/_includes/code/quickstart/quickstart.import_objects.mdx +++ b/_includes/code/quickstart/quickstart.import_objects.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/quickstart.import_object import TSCode from '!!raw-loader!/_includes/code/typescript/quickstart.import_objects.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart/2_2_add_objects/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart/Import.java'; @@ -64,6 +65,14 @@ During a batch import, any failed objects can be obtained through `batch.failed_ title="quickstart/Import.java" /> + + + diff --git a/_includes/code/quickstart/quickstart.is_ready.mdx b/_includes/code/quickstart/quickstart.is_ready.mdx index 1b27e20e5..af72f1d7d 100644 --- a/_includes/code/quickstart/quickstart.is_ready.mdx +++ b/_includes/code/quickstart/quickstart.is_ready.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/quickstart.is_ready.py'; import TSCode from '!!raw-loader!/_includes/code/typescript/quickstart.is_ready.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart/1_is_ready/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart/IsReady.java'; import HostnameWarning from '/_includes/wcs/hostname-warning.mdx'; @@ -63,6 +64,14 @@ import HostnameWarning from '/_includes/wcs/hostname-warning.mdx'; /> + + + diff --git a/_includes/code/quickstart/quickstart.query.neartext.mdx b/_includes/code/quickstart/quickstart.query.neartext.mdx index 6274866fe..89b7f8346 100644 --- a/_includes/code/quickstart/quickstart.query.neartext.mdx +++ b/_includes/code/quickstart/quickstart.query.neartext.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/quickstart.query.neartex import TSCode from '!!raw-loader!/_includes/code/typescript/quickstart.query.neartext.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart/3_1_neartext/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart/NearText.java'; @@ -61,6 +62,14 @@ import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/w title="quickstart/NearText.java" /> + + + diff --git a/_includes/code/quickstart/quickstart.query.rag.mdx b/_includes/code/quickstart/quickstart.query.rag.mdx index 0b665bbe9..dc5741384 100644 --- a/_includes/code/quickstart/quickstart.query.rag.mdx +++ b/_includes/code/quickstart/quickstart.query.rag.mdx @@ -5,6 +5,7 @@ import PyCode from '!!raw-loader!/_includes/code/python/quickstart.query.rag.py' import TSCode from '!!raw-loader!/_includes/code/typescript/quickstart.query.rag.ts'; import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/quickstart/3_2_rag/main.go'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/QuickstartTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/QuickstartTest.cs"; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/quickstart/RAG.java'; @@ -61,6 +62,14 @@ import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/w title="quickstart/RAG.java" /> + + + diff --git a/_includes/code/replication.get.object.by.id.mdx b/_includes/code/replication.get.object.by.id.mdx index 0b462a451..be0090629 100644 --- a/_includes/code/replication.get.object.by.id.mdx +++ b/_includes/code/replication.get.object.by.id.mdx @@ -4,6 +4,7 @@ import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBl import PyCode from '!!raw-loader!/_includes/code/howto/search.consistency.py'; import TSCode from '!!raw-loader!/_includes/code/howto/search.consistency.ts'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/SearchBasicTest.java"; +import CSharpCode from "!!raw-loader!/\_includes/code/csharp/SearchBasicTest.cs"; @@ -119,6 +120,14 @@ public class App { ``` + + + ```bash diff --git a/_includes/code/schema.things.properties.add.mdx b/_includes/code/schema.things.properties.add.mdx index d19ce6d6c..c8a4317a9 100644 --- a/_includes/code/schema.things.properties.add.mdx +++ b/_includes/code/schema.things.properties.add.mdx @@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl import PyCode from "!!raw-loader!/_includes/code/howto/manage-data.collections.py"; import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTest.cs"; @@ -85,4 +86,12 @@ func main() { language="java" /> + + + diff --git a/_includes/code/tutorial.schema.create.mdx b/_includes/code/tutorial.schema.create.mdx index 8d187ab93..26e1c36f5 100644 --- a/_includes/code/tutorial.schema.create.mdx +++ b/_includes/code/tutorial.schema.create.mdx @@ -1,8 +1,9 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/_includes/code/starter-guides/schema.py'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; +import PyCode from "!!raw-loader!/_includes/code/starter-guides/schema.py"; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/StarterGuidesCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/StarterGuidesCollectionsTest.cs"; @@ -23,6 +24,14 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Start language="java" /> + + + {/* ```go diff --git a/_includes/code/tutorial.schema.index-settings.mdx b/_includes/code/tutorial.schema.index-settings.mdx index c7f284489..07bef9f47 100644 --- a/_includes/code/tutorial.schema.index-settings.mdx +++ b/_includes/code/tutorial.schema.index-settings.mdx @@ -3,6 +3,7 @@ import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; import PyCode from '!!raw-loader!/_includes/code/starter-guides/schema.py'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/StarterGuidesCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/StarterGuidesCollectionsTest.cs"; @@ -23,6 +24,14 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Start language="java" /> + + + ```js diff --git a/_includes/code/tutorial.schema.multi-tenancy.mdx b/_includes/code/tutorial.schema.multi-tenancy.mdx index 982cf32ca..d0d58d45d 100644 --- a/_includes/code/tutorial.schema.multi-tenancy.mdx +++ b/_includes/code/tutorial.schema.multi-tenancy.mdx @@ -3,6 +3,7 @@ import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; import PyCode from '!!raw-loader!/_includes/code/starter-guides/schema.py'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/StarterGuidesCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/StarterGuidesCollectionsTest.cs"; @@ -23,6 +24,14 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Start language="java" /> + + + ```js diff --git a/_includes/code/tutorial.schema.properties.options.mdx b/_includes/code/tutorial.schema.properties.options.mdx index 258568b66..6cf0073cb 100644 --- a/_includes/code/tutorial.schema.properties.options.mdx +++ b/_includes/code/tutorial.schema.properties.options.mdx @@ -3,6 +3,7 @@ import TabItem from '@theme/TabItem'; import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; import PyCode from '!!raw-loader!/_includes/code/starter-guides/schema.py'; import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/StarterGuidesCollectionsTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/StarterGuidesCollectionsTest.cs"; @@ -23,6 +24,14 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Start language="java" /> + + + ```js diff --git a/_includes/schema-delete-class.mdx b/_includes/schema-delete-class.mdx index 348f2d40c..ad367c9a6 100644 --- a/_includes/schema-delete-class.mdx +++ b/_includes/schema-delete-class.mdx @@ -4,7 +4,7 @@ import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBl import ManageCollectionsCode from '!!raw-loader!/_includes/code/howto/manage-data.collections.py'; import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/manage-data.classes.java'; import JavaV6Code from '!!raw-loader!/_includes/code/java-v6/src/test/java/ManageCollectionsTest.java'; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ManageCollectionsTest.cs"; You can delete any unwanted collection(s), along with the data that they contain. diff --git a/_includes/weaviate-embeddings-vectorizer-parameters.mdx b/_includes/weaviate-embeddings-vectorizer-parameters.mdx index ba94a278c..1ec7f3558 100644 --- a/_includes/weaviate-embeddings-vectorizer-parameters.mdx +++ b/_includes/weaviate-embeddings-vectorizer-parameters.mdx @@ -1,12 +1,12 @@ - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock'; -import PyCode from '!!raw-loader!/docs/weaviate/model-providers/_includes/provider.vectorizer.py'; -import TSCode from '!!raw-loader!/docs/weaviate/model-providers/_includes/provider.vectorizer.ts'; -import GoCode from '!!raw-loader!/_includes/code/howto/go/docs/model-providers/2-usage-text/main.go'; -import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/ModelProvidersTest.java"; -import JavaCode from '!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/model_providers/UsageWeaviateTextEmbeddings.java'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; +import PyCode from "!!raw-loader!/docs/weaviate/model-providers/_includes/provider.vectorizer.py"; +import TSCode from "!!raw-loader!/docs/weaviate/model-providers/_includes/provider.vectorizer.ts"; +import GoCode from "!!raw-loader!/_includes/code/howto/go/docs/model-providers/2-usage-text/main.go"; +import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ModelProvidersTest.java"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/ModelProvidersTest.cs"; +import JavaCode from "!!raw-loader!/_includes/code/howto/java/src/test/java/io/weaviate/docs/model_providers/UsageWeaviateTextEmbeddings.java"; - `model` (optional): The name of the model to use for embedding generation. - `dimensions` (optional): The number of dimensions to use for the generated embeddings. @@ -23,23 +23,23 @@ The following examples show how to configure Weaviate Embeddings-specific option language="py" /> - - - - - - - + + + + + + + - - - + + + + + + diff --git a/docs/weaviate/client-libraries/csharp.mdx b/docs/weaviate/client-libraries/csharp.mdx index 983af4a32..6117b355e 100644 --- a/docs/weaviate/client-libraries/csharp.mdx +++ b/docs/weaviate/client-libraries/csharp.mdx @@ -9,7 +9,7 @@ image: og/docs/client-libraries.jpg import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBlock"; -import CSharpCode from "!!raw-loader!/_includes/code/csharp/GetStartedTests.cs"; +import CSharpCode from "!!raw-loader!/_includes/code/csharp/GetStartedTest.cs"; import QuickLinks from "/src/components/QuickLinks"; :::caution Preview diff --git a/docs/weaviate/configuration/compression/bq-compression.md b/docs/weaviate/configuration/compression/bq-compression.md index ab43b54dd..403292682 100644 --- a/docs/weaviate/configuration/compression/bq-compression.md +++ b/docs/weaviate/configuration/compression/bq-compression.md @@ -12,6 +12,7 @@ import TSCode from '!!raw-loader!/\_includes/code/howto/configure.bq-compression import TSCodeBQOptions from '!!raw-loader!/\_includes/code/howto/configure.bq-compression.options.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/configure/compression.bq_test.go'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/ConfigureBQTest.java"; +import CSharpCode from "!!raw-loader!/\_includes/code/csharp/ConfigureBQTest.cs"; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/bq-compression.java'; import CompressionByDefault from '/\_includes/compression-by-default.mdx'; @@ -74,6 +75,14 @@ BQ can be enabled at collection creation time through the collection definition: language="java" /> + + + ## Enable compression for existing collection @@ -117,6 +126,14 @@ BQ can also be enabled for an existing collection by updating the collection def language="java" /> + + + ## BQ parameters @@ -170,6 +187,14 @@ For example: language="java" /> + + + ## Additional considerations diff --git a/docs/weaviate/configuration/compression/pq-compression.md b/docs/weaviate/configuration/compression/pq-compression.md index d06647607..bf9a44477 100644 --- a/docs/weaviate/configuration/compression/pq-compression.md +++ b/docs/weaviate/configuration/compression/pq-compression.md @@ -12,6 +12,7 @@ import TSCodeAutoPQ from '!!raw-loader!/\_includes/code/howto/configure.pq-compr import TSCodeManualPQ from '!!raw-loader!/\_includes/code/howto/configure.pq-compression.manual.ts'; import GoCode from '!!raw-loader!/\_includes/code/howto/go/docs/configure/compression.pq_test.go'; import JavaV6Code from "!!raw-loader!/\_includes/code/java-v6/src/test/java/ConfigurePQTest.java"; +import CSharpCode from "!!raw-loader!/\_includes/code/csharp/ConfigurePQTest.cs"; import JavaCode from '!!raw-loader!/\_includes/code/howto/java/src/test/java/io/weaviate/docs/pq-compression.java'; import CompressionByDefault from '/\_includes/compression-by-default.mdx'; @@ -78,6 +79,14 @@ To configure PQ in a collection, use the [PQ parameters](./pq-compression.md#pq- language="java" /> + + + ### 3. Load your data @@ -155,6 +164,14 @@ Follow these steps to manually enable PQ. language="java" /> + + + ### 2. Load training data @@ -216,6 +233,14 @@ To enable PQ, update your collection definition as shown below. For additional c language="java" /> + + + ### 4. Load the rest of your data @@ -307,6 +332,14 @@ To review the current `pq` configuration, you can retrieve it as shown below. language="java" /> + + + ### Multiple vector embeddings (named vectors) diff --git a/docs/weaviate/configuration/compression/rq-compression.md b/docs/weaviate/configuration/compression/rq-compression.md index 6a91e0458..2d27beb13 100644 --- a/docs/weaviate/configuration/compression/rq-compression.md +++ b/docs/weaviate/configuration/compression/rq-compression.md @@ -83,6 +83,14 @@ RQ can be enabled at collection creation time through the collection definition: language="java" /> + + + ### Enable compression for existing collection @@ -114,6 +122,14 @@ RQ can also be enabled for an existing collection by updating the collection def language="java" /> + + + + + + ### Enable compression for existing collection @@ -221,6 +245,14 @@ RQ can also be enabled for an existing collection by updating the collection def language="java" /> + + + ## RQ parameters @@ -272,6 +304,14 @@ import RQParameters from '/\_includes/configuration/rq-compression-parameters.md language="java" /> + + +