From 0c0101408b08709f62bc5bce9fd399efe90efd27 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 11 Aug 2025 21:51:33 -0500 Subject: [PATCH] add order by --- .../VectorStorage/Models/VectorFilter.cs | 9 +++++++ .../VectorStorage/Models/VectorSort.cs | 10 ++++++++ .../BotSharp.Plugin.Qdrant/QdrantDb.cs | 24 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSort.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs index 88a1aca4..43ce6e04 100644 --- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs +++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs @@ -9,11 +9,20 @@ public class VectorFilter : StringIdPagination /// Filter group: each item contains a logical operator and a list of key-value pairs /// [JsonPropertyName("filter_groups")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IEnumerable? FilterGroups { get; set; } + /// + /// Order by a specific field + /// + [JsonPropertyName("order_by")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public VectorSort? OrderBy { get; set; } + /// /// Included payload fields /// [JsonPropertyName("fields")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IEnumerable? Fields { get; set; } } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSort.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSort.cs new file mode 100644 index 00000000..469018b0 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSort.cs @@ -0,0 +1,10 @@ +namespace BotSharp.Abstraction.VectorStorage.Models; + +public class VectorSort +{ + [JsonPropertyName("field")] + public string? Field { get; set; } + + [JsonPropertyName("order")] + public string? Order { get; set; } = "desc"; +} diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs index f5465c32..9841ddab 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs +++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs @@ -144,6 +144,7 @@ public class QdrantDb : IVectorDb Filter? queryFilter = BuildQueryFilter(filter.FilterGroups); WithPayloadSelector? payloadSelector = BuildPayloadSelector(filter.Fields); + OrderBy? orderBy = BuildOrderBy(filter.OrderBy); var client = GetClient(); var tasks = new List(); @@ -154,6 +155,7 @@ public class QdrantDb : IVectorDb limit: (uint)filter.Size, offset: !string.IsNullOrWhiteSpace(filter.StartId) ? new PointId { Uuid = filter.StartId } : null, filter: queryFilter, + orderBy: orderBy, payloadSelector: payloadSelector, vectorsSelector: filter.WithVector); @@ -371,7 +373,13 @@ public class QdrantDb : IVectorDb var client = GetClient(); var schemaType = ConvertPayloadSchemaType(options.FieldSchemaType); - var result = await client.CreatePayloadIndexAsync(collectionName, options.FieldName, schemaType); + var result = await client.CreatePayloadIndexAsync(collectionName, options.FieldName, schemaType, indexParams: new() + { + IntegerIndexParams = new() + { + Range = true + } + }); return result.Status == UpdateStatus.Completed; } @@ -618,6 +626,20 @@ public class QdrantDb : IVectorDb return payloadSelector; } + private OrderBy? BuildOrderBy(VectorSort? sort) + { + if (string.IsNullOrWhiteSpace(sort?.Field)) + { + return null; + } + + return new OrderBy + { + Key = sort.Field, + Direction = sort.Order == "asc" ? Direction.Asc : Direction.Desc + }; + } + private PayloadSchemaType ConvertPayloadSchemaType(string schemaType) { PayloadSchemaType res;