|
@@ -0,0 +1,101 @@
|
|
|
+using System.Text;
|
|
|
+using Hotline.Repository.SqlSugar.TextSearch;
|
|
|
+using NpgsqlTypes;
|
|
|
+using SqlSugar;
|
|
|
+using XF.Domain.Dependency;
|
|
|
+using XF.Domain.Entities;
|
|
|
+using XF.Domain.Extensions;
|
|
|
+
|
|
|
+namespace Hotline.Repository.SqlSugar;
|
|
|
+
|
|
|
+public abstract class BaseRepositoryTextSearch<TEntity> : IRepositoryTextSearch<TEntity>, IScopeDependency
|
|
|
+ where TEntity : class, IEntity<string>, ITextSearch, new()
|
|
|
+{
|
|
|
+ private readonly ISugarUnitOfWork<HotlineDbContext> _uow;
|
|
|
+ private readonly ISqlSugarClient _db;
|
|
|
+
|
|
|
+ public BaseRepositoryTextSearch(ISugarUnitOfWork<HotlineDbContext> uow)
|
|
|
+ {
|
|
|
+ _uow = uow;
|
|
|
+ _db = uow.Db;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 全都采用默认权重
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="id">原始数据Id</param>
|
|
|
+ /// <param name="creationTime">原始数据CreationTime</param>
|
|
|
+ /// <param name="texts"></param>
|
|
|
+ /// <param name="cancellationToken"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public Task AddVectorAsync(string id, DateTime creationTime, ICollection<string> texts, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var weights = texts.Select(d => new NpgsqlWeight
|
|
|
+ {
|
|
|
+ Text = d
|
|
|
+ }).ToList();
|
|
|
+ return AddVectorAsync(id, creationTime, weights, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 自定义权重
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="id">原始数据Id</param>
|
|
|
+ /// <param name="creationTime">原始数据CreationTime</param>
|
|
|
+ /// <param name="cancellationToken"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task AddVectorAsync(string id, DateTime creationTime, ICollection<NpgsqlWeight> weights, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var tableName = typeof(TEntity).Name.ToSnakeCase();
|
|
|
+ var vectorSql = CreateVectorSql(weights);
|
|
|
+ var sql = $"INSERT INTO @tableName VALUES ('@id', '@creationTime', @vector)";
|
|
|
+ await _db.Ado.ExecuteCommandAsync(sql, new { tableName, id, creationTime, vector = vectorSql }, cancellationToken);
|
|
|
+ /*
|
|
|
+ INSERT INTO "order_ts" VALUES ('f595e730-909a-45e4-9138-a84bf15f4660', '2023-09-06 10:51:38', setweight(to_tsvector('simple', 'aa'), 'C') || setweight(to_tsvector('simple', 'bb'), 'C'))
|
|
|
+ */
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 全都采用默认权重
|
|
|
+ /// </summary>
|
|
|
+ public Task UpdateVectorAsync(string id, ICollection<string> texts, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var weights = texts.Select(d => new NpgsqlWeight
|
|
|
+ {
|
|
|
+ Text = d
|
|
|
+ }).ToList();
|
|
|
+ return UpdateVectorAsync(id, weights, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 自定义权重
|
|
|
+ /// </summary>
|
|
|
+ public async Task UpdateVectorAsync(string id, ICollection<NpgsqlWeight> weights, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var tableName = typeof(TEntity).Name.ToSnakeCase();
|
|
|
+ var vectorSql = CreateVectorSql(weights);
|
|
|
+ var sql = $"UPDATE @tableName SET \"Vector\"=@vector WHERE id=@id ";
|
|
|
+ await _db.Ado.ExecuteCommandAsync(sql, new { tableName, id, vector = vectorSql }, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<List<RankedResult<TEntity>>> SearchAsync(IReadOnlyList<string> texts, CancellationToken cancellationToken)
|
|
|
+ {
|
|
|
+ var tableName = typeof(TEntity).Name.ToSnakeCase();
|
|
|
+ var tsquery = string.Join(' ', texts);
|
|
|
+ var sql = "SELECT Id, CreationTime, Vector, Texts, ts_rank(\"Vector\", query) AS score FROM @tableName to_tsquery('simple', @tsquery) query WHERE \"Vector\" @@ query ORDER BY score DESC)";
|
|
|
+ return await _db.Ado.SqlQueryAsync<RankedResult<TEntity>>(sql, new { tableName, tsquery }, cancellationToken);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ #region private method
|
|
|
+
|
|
|
+ private static string CreateVectorSql(ICollection<NpgsqlWeight> weights)
|
|
|
+ {
|
|
|
+ var setweghtStrings = weights.Select(d => $"setweight(to_tsvector('simple', {d.Text}), '{d.Weight}')");
|
|
|
+ var vectorString = string.Join(" || ", setweghtStrings);
|
|
|
+ return vectorString;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+}
|