refine vector filter
This commit is contained in:
parent
5bb5d69894
commit
0e2fb847a7
|
|
@ -6,16 +6,10 @@ public class VectorFilter : StringIdPagination
|
|||
public bool WithVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For keyword search
|
||||
/// Filter group: each item contains a logical operator and a list of key-value pairs
|
||||
/// </summary>
|
||||
[JsonPropertyName("filters")]
|
||||
public IEnumerable<KeyValue>? Filters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filter operator
|
||||
/// </summary>
|
||||
[JsonPropertyName("filter_operator")]
|
||||
public string FilterOperator { get; set; } = "or";
|
||||
[JsonPropertyName("filter_groups")]
|
||||
public IEnumerable<VectorFilterGroup>? FilterGroups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Included payload fields
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
namespace BotSharp.Abstraction.VectorStorage.Models;
|
||||
|
||||
public class VectorFilterGroup
|
||||
{
|
||||
[JsonPropertyName("filters")]
|
||||
public IEnumerable<KeyValue>? Filters { get; set; }
|
||||
|
||||
[JsonPropertyName("filter_operator")]
|
||||
public string FilterOperator { get; set; } = "or";
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@ namespace BotSharp.Abstraction.VectorStorage.Models;
|
|||
public class VectorSearchOptions
|
||||
{
|
||||
public IEnumerable<string>? Fields { get; set; } = [KnowledgePayloadName.Text, KnowledgePayloadName.Answer];
|
||||
public IEnumerable<KeyValue>? Filters { get; set; }
|
||||
public string FilterOperator { get; set; } = "or";
|
||||
public IEnumerable<VectorFilterGroup>? FilterGroups { get; set; }
|
||||
public int? Limit { get; set; } = 5;
|
||||
public float? Confidence { get; set; } = 0.5f;
|
||||
public bool WithVector { get; set; }
|
||||
|
|
@ -16,8 +15,7 @@ public class VectorSearchOptions
|
|||
return new()
|
||||
{
|
||||
Fields = [KnowledgePayloadName.Text, KnowledgePayloadName.Answer],
|
||||
Filters = null,
|
||||
FilterOperator = "or",
|
||||
FilterGroups = null,
|
||||
Limit = 5,
|
||||
Confidence = 0.5f,
|
||||
WithVector = false
|
||||
|
|
|
|||
|
|
@ -60,8 +60,7 @@ public class KnowledgeBaseController : ControllerBase
|
|||
var options = new VectorSearchOptions
|
||||
{
|
||||
Fields = request.Fields,
|
||||
Filters = request.Filters,
|
||||
FilterOperator = request.FilterOperator,
|
||||
FilterGroups = request.FilterGroups,
|
||||
Limit = request.Limit ?? 5,
|
||||
Confidence = request.Confidence ?? 0.5f,
|
||||
WithVector = request.WithVector
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using BotSharp.Abstraction.VectorStorage.Models;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.OpenAPI.ViewModels.Knowledges;
|
||||
|
|
@ -10,11 +11,8 @@ public class SearchVectorKnowledgeRequest
|
|||
[JsonPropertyName("fields")]
|
||||
public IEnumerable<string>? Fields { get; set; }
|
||||
|
||||
[JsonPropertyName("filters")]
|
||||
public IEnumerable<KeyValue>? Filters { get; set; }
|
||||
|
||||
[JsonPropertyName("filter_operator")]
|
||||
public string FilterOperator { get; set; } = "or";
|
||||
[JsonPropertyName("filter_groups")]
|
||||
public IEnumerable<VectorFilterGroup>? FilterGroups { get; set; }
|
||||
|
||||
[JsonPropertyName("limit")]
|
||||
public int? Limit { get; set; } = 5;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class VectorKnowledgeCreateRequest
|
|||
public string Text { get; set; }
|
||||
|
||||
[JsonPropertyName("data_source")]
|
||||
public string DataSource { get; set; } = VectorDataSource.Api;
|
||||
public string DataSource { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("payload")]
|
||||
public Dictionary<string, object>? Payload { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using BotSharp.Abstraction.Files;
|
||||
using BotSharp.Abstraction.VectorStorage.Enums;
|
||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
|
||||
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
|
|
@ -165,7 +166,12 @@ public partial class KnowledgeService
|
|||
var db = GetVectorDb();
|
||||
var guid = Guid.NewGuid();
|
||||
var payload = create.Payload ?? new();
|
||||
payload[KnowledgePayloadName.DataSource] = !string.IsNullOrWhiteSpace(create.DataSource) ? create.DataSource : VectorDataSource.Api;
|
||||
|
||||
if (!payload.TryGetValue(KnowledgePayloadName.DataSource, out _))
|
||||
{
|
||||
payload[KnowledgePayloadName.DataSource] = !string.IsNullOrWhiteSpace(create.DataSource) ?
|
||||
create.DataSource : VectorDataSource.Api;
|
||||
}
|
||||
|
||||
return await db.Upsert(collectionName, guid, vector, create.Text, payload);
|
||||
}
|
||||
|
|
@ -198,7 +204,12 @@ public partial class KnowledgeService
|
|||
var textEmbedding = GetTextEmbedding(collectionName);
|
||||
var vector = await textEmbedding.GetVectorAsync(update.Text);
|
||||
var payload = update.Payload ?? new();
|
||||
payload[KnowledgePayloadName.DataSource] = !string.IsNullOrWhiteSpace(update.DataSource) ? update.DataSource : VectorDataSource.Api;
|
||||
|
||||
if (!payload.TryGetValue(KnowledgePayloadName.DataSource, out _))
|
||||
{
|
||||
payload[KnowledgePayloadName.DataSource] = !string.IsNullOrWhiteSpace(update.DataSource) ?
|
||||
update.DataSource : VectorDataSource.Api;
|
||||
}
|
||||
|
||||
return await db.Upsert(collectionName, guid, vector, update.Text, payload);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public class QdrantDb : IVectorDb
|
|||
return new StringIdPagedItems<VectorCollectionData>();
|
||||
}
|
||||
|
||||
Filter? queryFilter = BuildQueryFilter(filter.Filters, filter.FilterOperator);
|
||||
Filter? queryFilter = BuildQueryFilter(filter.FilterGroups);
|
||||
WithPayloadSelector? payloadSelector = BuildPayloadSelector(filter.Fields);
|
||||
|
||||
var client = GetClient();
|
||||
|
|
@ -237,7 +237,10 @@ public class QdrantDb : IVectorDb
|
|||
foreach (var item in payload)
|
||||
{
|
||||
var value = item.Value?.ToString();
|
||||
if (value == null) continue;
|
||||
if (value == null || item.Key.IsEqualTo(KnowledgePayloadName.Text))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bool.TryParse(value, out var b))
|
||||
{
|
||||
|
|
@ -298,7 +301,7 @@ public class QdrantDb : IVectorDb
|
|||
}
|
||||
|
||||
options ??= VectorSearchOptions.Default();
|
||||
Filter? queryFilter = BuildQueryFilter(options.Filters, options.FilterOperator);
|
||||
Filter? queryFilter = BuildQueryFilter(options.FilterGroups);
|
||||
WithPayloadSelector? payloadSelector = BuildPayloadSelector(options.Fields);
|
||||
|
||||
var client = GetClient();
|
||||
|
|
@ -533,49 +536,66 @@ public class QdrantDb : IVectorDb
|
|||
|
||||
|
||||
#region Private methods
|
||||
private Filter? BuildQueryFilter(IEnumerable<KeyValue>? keyValues, string op)
|
||||
private Filter? BuildQueryFilter(IEnumerable<VectorFilterGroup>? filterGroups)
|
||||
{
|
||||
Filter? queryFilter = null;
|
||||
if (!keyValues.IsNullOrEmpty())
|
||||
|
||||
if (filterGroups.IsNullOrEmpty())
|
||||
{
|
||||
var conditions = keyValues.Select(x =>
|
||||
return queryFilter;
|
||||
}
|
||||
|
||||
var conditions = filterGroups.Where(x => !x.Filters.IsNullOrEmpty()).Select(x =>
|
||||
{
|
||||
Filter filter;
|
||||
var innerConditions = x.Filters.Select(f =>
|
||||
{
|
||||
var field = new FieldCondition
|
||||
{
|
||||
Key = x.Key,
|
||||
Match = new Match { Text = x.Value },
|
||||
Key = f.Key,
|
||||
Match = new Match { Text = f.Value },
|
||||
};
|
||||
|
||||
if (bool.TryParse(x.Value, out var boolVal))
|
||||
if (bool.TryParse(f.Value, out var boolVal))
|
||||
{
|
||||
field.Match = new Match { Boolean = boolVal };
|
||||
}
|
||||
else if (long.TryParse(x.Value, out var intVal))
|
||||
else if (long.TryParse(f.Value, out var intVal))
|
||||
{
|
||||
field.Match = new Match { Integer = intVal };
|
||||
}
|
||||
|
||||
return new Condition
|
||||
{
|
||||
Field = field
|
||||
};
|
||||
return new Condition { Field = field };
|
||||
});
|
||||
|
||||
if (op.IsEqualTo("and"))
|
||||
if (x.FilterOperator.IsEqualTo("and"))
|
||||
{
|
||||
queryFilter = new Filter
|
||||
filter = new Filter
|
||||
{
|
||||
Must = { conditions }
|
||||
Must = { innerConditions }
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
queryFilter = new Filter
|
||||
filter = new Filter
|
||||
{
|
||||
Should = { conditions }
|
||||
Should = { innerConditions }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new Condition
|
||||
{
|
||||
Filter = filter
|
||||
};
|
||||
});
|
||||
|
||||
queryFilter = new Filter
|
||||
{
|
||||
Must =
|
||||
{
|
||||
conditions
|
||||
}
|
||||
};
|
||||
|
||||
return queryFilter;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue