add payload index

This commit is contained in:
Jicheng Lu 2025-08-06 10:14:22 -05:00
parent de3b36368c
commit 7e40dd9262
8 changed files with 195 additions and 16 deletions

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Graph.Models;
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.VectorStorage.Models;
namespace BotSharp.Abstraction.Knowledges;
@ -69,6 +70,11 @@ public interface IKnowledgeService
Task<bool> DeleteVectorCollectionSnapshot(string collectionName, string snapshotName);
#endregion
#region Index
Task<SuccessFailResponse<string>> CreateVectorCollectionPayloadIndexes(string collectionName, IEnumerable<CreateVectorCollectionIndexOptions> options);
Task<SuccessFailResponse<string>> DeleteVectorCollectionPayloadIndexes(string collectionName, IEnumerable<DeleteVectorCollectionIndexOptions> options);
#endregion
#region Common
Task<bool> RefreshVectorKnowledgeConfigs(VectorCollectionConfigsModel configs);
#endregion

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Models;
public class SuccessFailResponse<T>
{
public List<T> Success { get; set; } = [];
public List<T> Fail { get; set; } = [];
}

View file

@ -39,4 +39,9 @@ public interface IVectorDb
=> throw new NotImplementedException();
Task<bool> DeleteCollectionShapshot(string collectionName, string snapshotName)
=> throw new NotImplementedException();
Task<bool> CreateCollectionPayloadIndex(string collectionName, CreateVectorCollectionIndexOptions options)
=> throw new NotImplementedException();
Task<bool> DeleteCollectionPayloadIndex(string collectionName, DeleteVectorCollectionIndexOptions options)
=> throw new NotImplementedException();
}

View file

@ -0,0 +1,18 @@
namespace BotSharp.Abstraction.VectorStorage.Models;
public class VectorCollectionIndexOptions
{
[JsonPropertyName("field_name")]
public string FieldName { get; set; } = null!;
}
public class CreateVectorCollectionIndexOptions : VectorCollectionIndexOptions
{
[JsonPropertyName("field_schema_type")]
public string FieldSchemaType { get; set; } = null!;
}
public class DeleteVectorCollectionIndexOptions : VectorCollectionIndexOptions
{
}

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Files.Utilities;
using BotSharp.Abstraction.Graph.Models;
using BotSharp.Abstraction.VectorStorage.Models;
using BotSharp.OpenAPI.ViewModels.Knowledges;
using BotSharp.OpenAPI.ViewModels.Knowledges.Request;
namespace BotSharp.OpenAPI.Controllers;
@ -125,16 +126,16 @@ public class KnowledgeBaseController : ControllerBase
return await _knowledgeService.DeleteVectorCollectionAllData(collection);
}
[HttpPost("/knowledge/vector/{collection}/payload/index")]
public async Task<bool> CreateCollectionPayloadIndex()
[HttpPost("/knowledge/vector/{collection}/payload/indexes")]
public async Task<SuccessFailResponse<string>> CreateCollectionPayloadIndexes([FromRoute] string collection, [FromBody] CreateVectorCollectionIndexRequest request)
{
return false;
return await _knowledgeService.CreateVectorCollectionPayloadIndexes(collection, request.Options);
}
[HttpDelete("/knowledge/vector/{collection}/payload/index")]
public async Task<bool> DeleteCollectionPayloadIndex()
[HttpDelete("/knowledge/vector/{collection}/payload/indexes")]
public async Task<SuccessFailResponse<string>> DeleteCollectionPayloadIndexes([FromRoute] string collection, [FromBody] DeleteVectorCollectionIndexRequest request)
{
return false;
return await _knowledgeService.DeleteVectorCollectionPayloadIndexes(collection, request.Options);
}
#endregion

View file

@ -0,0 +1,13 @@
using BotSharp.Abstraction.VectorStorage.Models;
namespace BotSharp.OpenAPI.ViewModels.Knowledges.Request;
public class CreateVectorCollectionIndexRequest
{
public IEnumerable<CreateVectorCollectionIndexOptions> Options { get; set; } = [];
}
public class DeleteVectorCollectionIndexRequest
{
public IEnumerable<DeleteVectorCollectionIndexOptions> Options { get; set; } = [];
}

View file

@ -0,0 +1,74 @@
using BotSharp.Abstraction.Models;
namespace BotSharp.Plugin.KnowledgeBase.Services;
public partial class KnowledgeService
{
public async Task<SuccessFailResponse<string>> CreateVectorCollectionPayloadIndexes(string collectionName, IEnumerable<CreateVectorCollectionIndexOptions> options)
{
try
{
if (string.IsNullOrWhiteSpace(collectionName) || options.IsNullOrEmpty())
{
return new();
}
var response = new SuccessFailResponse<string>();
var vectorDb = GetVectorDb();
foreach (var option in options)
{
var created = await vectorDb.CreateCollectionPayloadIndex(collectionName, option);
var field = $"{option.FieldName}-{option.FieldSchemaType}";
if (created)
{
response.Success.Add(field);
}
else
{
_logger.LogError($"Failed to create vector collection payload index ({collectionName}-{field}).");
response.Fail.Add(field);
}
}
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error when creating vector collection payload index ({collectionName}).");
return new();
}
}
public async Task<SuccessFailResponse<string>> DeleteVectorCollectionPayloadIndexes(string collectionName, IEnumerable<DeleteVectorCollectionIndexOptions> options)
{
try
{
if (string.IsNullOrWhiteSpace(collectionName) || options.IsNullOrEmpty())
{
return new();
}
var response = new SuccessFailResponse<string>();
var vectorDb = GetVectorDb();
foreach (var option in options)
{
var deleted = await vectorDb.DeleteCollectionPayloadIndex(collectionName, option);
var field = $"{option.FieldName}";
if (deleted)
{
response.Success.Add(field);
}
else
{
_logger.LogError($"Failed to deleting vector collection payload index ({collectionName}-{field}).");
response.Fail.Add(field);
}
}
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error when deleting vector collection payload index ({collectionName}).");
return new();
}
}
}

View file

@ -402,17 +402,32 @@ public class QdrantDb : IVectorDb
}
//public async Task<bool> CreateCollectionPayloadIndex(string collectionName)
//{
// var exist = await DoesCollectionExist(collectionName);
// if (!exist)
// {
// return false;
// }
public async Task<bool> CreateCollectionPayloadIndex(string collectionName, CreateVectorCollectionIndexOptions options)
{
var exist = await DoesCollectionExist(collectionName);
if (!exist)
{
return false;
}
// var client = GetClient();
// var result = await client.CreatePayloadIndexAsync(collectionName, "text", PayloadSchemaType.Keyword);
//}
var client = GetClient();
var schemaType = ConvertPayloadSchemaType(options.FieldSchemaType);
var result = await client.CreatePayloadIndexAsync(collectionName, options.FieldName, schemaType);
return result.Status == UpdateStatus.Completed;
}
public async Task<bool> DeleteCollectionPayloadIndex(string collectionName, DeleteVectorCollectionIndexOptions options)
{
var exist = await DoesCollectionExist(collectionName);
if (!exist)
{
return false;
}
var client = GetClient();
var result = await client.DeletePayloadIndexAsync(collectionName, options.FieldName);
return result.Status == UpdateStatus.Completed;
}
#endregion
#region Snapshots
@ -559,4 +574,44 @@ public class QdrantDb : IVectorDb
}
}
#endregion
#region Private methods
private PayloadSchemaType ConvertPayloadSchemaType(string schemaType)
{
PayloadSchemaType res;
switch (schemaType.ToLower())
{
case "text":
res = PayloadSchemaType.Text;
break;
case "keyword":
res = PayloadSchemaType.Keyword;
break;
case "integer":
res = PayloadSchemaType.Integer;
break;
case "float":
res = PayloadSchemaType.Float;
break;
case "bool":
res = PayloadSchemaType.Bool;
break;
case "geo":
res = PayloadSchemaType.Geo;
break;
case "datetime":
res = PayloadSchemaType.Datetime;
break;
case "uuid":
res = PayloadSchemaType.Uuid;
break;
default:
res = PayloadSchemaType.UnknownType;
break;
}
return res;
}
#endregion
}