Added query cache size limiting, added custom enumerable LRUCache, renamed search to query in various places, fixed client GetEmbeddingsCacheSize endpoint
This commit is contained in:
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Server.Exceptions;
|
||||
using Server.Helper;
|
||||
using Shared;
|
||||
using Shared.Models;
|
||||
|
||||
namespace Server.Controllers;
|
||||
@@ -134,13 +135,13 @@ public class SearchdomainController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="searchdomain">Name of the searchdomain</param>
|
||||
[HttpGet("Queries")]
|
||||
public ActionResult<SearchdomainSearchesResults> GetQueries([Required]string searchdomain)
|
||||
public ActionResult<SearchdomainQueriesResults> GetQueries([Required]string searchdomain)
|
||||
{
|
||||
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
|
||||
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
|
||||
Dictionary<string, DateTimedSearchResult> searchCache = searchdomain_.searchCache;
|
||||
Dictionary<string, DateTimedSearchResult> searchCache = searchdomain_.queryCache.AsDictionary();
|
||||
|
||||
return Ok(new SearchdomainSearchesResults() { Searches = searchCache, Success = true });
|
||||
return Ok(new SearchdomainQueriesResults() { Searches = searchCache, Success = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -175,7 +176,7 @@ public class SearchdomainController : ControllerBase
|
||||
{
|
||||
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
|
||||
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
|
||||
Dictionary<string, DateTimedSearchResult> searchCache = searchdomain_.searchCache;
|
||||
EnumerableLruCache<string, DateTimedSearchResult> searchCache = searchdomain_.queryCache;
|
||||
bool containsKey = searchCache.ContainsKey(query);
|
||||
if (containsKey)
|
||||
{
|
||||
@@ -196,7 +197,7 @@ public class SearchdomainController : ControllerBase
|
||||
{
|
||||
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
|
||||
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
|
||||
Dictionary<string, DateTimedSearchResult> searchCache = searchdomain_.searchCache;
|
||||
EnumerableLruCache<string, DateTimedSearchResult> searchCache = searchdomain_.queryCache;
|
||||
bool containsKey = searchCache.ContainsKey(query);
|
||||
if (containsKey)
|
||||
{
|
||||
@@ -237,6 +238,7 @@ public class SearchdomainController : ControllerBase
|
||||
};
|
||||
searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set settings = @settings WHERE id = @id", parameters);
|
||||
searchdomain_.settings = request;
|
||||
searchdomain_.queryCache.Capacity = request.QueryCacheSize;
|
||||
return Ok(new SearchdomainUpdateResults(){Success = true});
|
||||
}
|
||||
|
||||
@@ -245,15 +247,17 @@ public class SearchdomainController : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="searchdomain">Name of the searchdomain</param>
|
||||
[HttpGet("QueryCache/Size")]
|
||||
public ActionResult<SearchdomainSearchCacheSizeResults> GetSearchCacheSize([Required]string searchdomain)
|
||||
public ActionResult<SearchdomainQueryCacheSizeResults> GetQueryCacheSize([Required]string searchdomain)
|
||||
{
|
||||
if (!SearchdomainHelper.IsSearchdomainLoaded(_domainManager, searchdomain))
|
||||
{
|
||||
return Ok(new SearchdomainSearchCacheSizeResults() { QueryCacheSizeBytes = 0, Success = true });
|
||||
return Ok(new SearchdomainQueryCacheSizeResults() { SizeBytes = 0, ElementCount = 0, ElementMaxCount = 0, Success = true });
|
||||
}
|
||||
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
|
||||
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
|
||||
return Ok(new SearchdomainSearchCacheSizeResults() { QueryCacheSizeBytes = searchdomain_.GetSearchCacheSize(), Success = true });
|
||||
int elementCount = searchdomain_.queryCache.Count();
|
||||
int ElementMaxCount = searchdomain_.settings.QueryCacheSize;
|
||||
return Ok(new SearchdomainQueryCacheSizeResults() { SizeBytes = searchdomain_.GetSearchCacheSize(), ElementCount = elementCount, ElementMaxCount = ElementMaxCount, Success = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text.Json;
|
||||
using ElmahCore.Mvc.Logger;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Server.Helper;
|
||||
using Shared;
|
||||
using Shared.Models;
|
||||
using AdaptiveExpressions;
|
||||
|
||||
@@ -17,7 +18,7 @@ public class Searchdomain
|
||||
public string searchdomain;
|
||||
public int id;
|
||||
public SearchdomainSettings settings;
|
||||
public Dictionary<string, DateTimedSearchResult> searchCache; // Key: query, Value: Search results for that query (with timestamp)
|
||||
public EnumerableLruCache<string, DateTimedSearchResult> queryCache; // Key: query, Value: Search results for that query (with timestamp)
|
||||
public List<Entity> entityCache;
|
||||
public List<string> modelsInUse;
|
||||
public LRUCache<string, Dictionary<string, float[]>> embeddingCache;
|
||||
@@ -33,12 +34,12 @@ public class Searchdomain
|
||||
this.aIProvider = aIProvider;
|
||||
this.embeddingCache = embeddingCache;
|
||||
this._logger = logger;
|
||||
searchCache = [];
|
||||
entityCache = [];
|
||||
connection = new MySqlConnection(connectionString);
|
||||
connection.Open();
|
||||
helper = new SQLHelper(connection, connectionString);
|
||||
settings = GetSettings();
|
||||
queryCache = new(settings.QueryCacheSize);
|
||||
modelsInUse = []; // To make the compiler shut up - it is set in UpdateSearchDomain() don't worry // yeah, about that...
|
||||
if (!runEmpty)
|
||||
{
|
||||
@@ -163,7 +164,7 @@ public class Searchdomain
|
||||
|
||||
public List<(float, string)> Search(string query, int? topN = null)
|
||||
{
|
||||
if (searchCache.TryGetValue(query, out DateTimedSearchResult cachedResult))
|
||||
if (queryCache.TryGetValue(query, out DateTimedSearchResult cachedResult))
|
||||
{
|
||||
cachedResult.AccessDateTimes.Add(DateTime.Now);
|
||||
return [.. cachedResult.Results.Select(r => (r.Score, r.Name))];
|
||||
@@ -187,7 +188,7 @@ public class Searchdomain
|
||||
[.. sortedResults.Select(r =>
|
||||
new ResultItem(r.Item1, r.Item2 ))]
|
||||
);
|
||||
searchCache[query] = new DateTimedSearchResult(DateTime.Now, searchResult);
|
||||
queryCache.Set(query, new DateTimedSearchResult(DateTime.Now, searchResult));
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ public class Searchdomain
|
||||
{
|
||||
if (settings.CacheReconciliation)
|
||||
{
|
||||
foreach (KeyValuePair<string, DateTimedSearchResult> element in searchCache)
|
||||
foreach (var element in queryCache)
|
||||
{
|
||||
string query = element.Key;
|
||||
DateTimedSearchResult searchResult = element.Value;
|
||||
@@ -322,7 +323,7 @@ public class Searchdomain
|
||||
{
|
||||
if (settings.CacheReconciliation)
|
||||
{
|
||||
foreach (KeyValuePair<string, DateTimedSearchResult> element in searchCache)
|
||||
foreach (KeyValuePair<string, DateTimedSearchResult> element in queryCache)
|
||||
{
|
||||
string query = element.Key;
|
||||
DateTimedSearchResult searchResult = element.Value;
|
||||
@@ -337,13 +338,13 @@ public class Searchdomain
|
||||
|
||||
public void InvalidateSearchCache()
|
||||
{
|
||||
searchCache = [];
|
||||
queryCache = new(settings.QueryCacheSize);
|
||||
}
|
||||
|
||||
public long GetSearchCacheSize()
|
||||
{
|
||||
long sizeInBytes = 0;
|
||||
foreach (var entry in searchCache)
|
||||
foreach (var entry in queryCache)
|
||||
{
|
||||
sizeInBytes += sizeof(int); // string length prefix
|
||||
sizeInBytes += entry.Key.Length * sizeof(char); // string characters
|
||||
|
||||
@@ -62,11 +62,17 @@
|
||||
<!-- Settings -->
|
||||
<div class="row align-items-center mb-3">
|
||||
<h3>@T["Settings"]</h3>
|
||||
<div class="col-md-3">
|
||||
<label class="form-check-label" for="searchdomainConfigQueryCacheSize">@T["Query cache size"]:</label>
|
||||
<input type="number" class="form-control" id="searchdomainConfigQueryCacheSize" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<input type="checkbox" class="form-check-input" id="searchdomainConfigCacheReconciliation" />
|
||||
<label class="form-check-label" for="searchdomainConfigCacheReconciliation">@T["Cache reconciliation"]</label>
|
||||
</div>
|
||||
<div class="col-md-2 mt-3 mt-md-0">
|
||||
</div>
|
||||
<div class="row align-items-center mb-3">
|
||||
<div class="col-md-2 mt-md-0">
|
||||
<button class="btn btn-warning w-100" id="searchdomainConfigUpdate">@T["Update"]</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -347,10 +353,20 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<label for="createSearchdomainName" class="form-label">@T["Searchdomain name"]</label>
|
||||
<input type="text" class="form-control mb-3" id="createSearchdomainName" placeholder="@T["Searchdomain name"]" />
|
||||
<input type="checkbox" class="form-check-input" id="createSearchdomainWithCacheReconciliation" />
|
||||
<label class="form-check-label" for="createSearchdomainWithCacheReconciliation">@T["Enable cache reconciliation"]</label>
|
||||
<div class="row align-items-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<label for="createSearchdomainName" class="form-label">@T["Searchdomain name"]</label>
|
||||
<input type="text" class="form-control mb-3" id="createSearchdomainName" placeholder="@T["Searchdomain name"]" />
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label class="form-check-label mb-2" for="createSearchdomainQueryCacheSize">@T["Query cache size"]:</label>
|
||||
<input type="number" class="form-control" id="createSearchdomainQueryCacheSize" />
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<input type="checkbox" class="form-check-input" id="createSearchdomainWithCacheReconciliation" />
|
||||
<label class="form-check-label" for="createSearchdomainWithCacheReconciliation">@T["Enable cache reconciliation"]</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
@@ -694,7 +710,8 @@
|
||||
.addEventListener('click', () => {
|
||||
const domainKey = getSelectedDomainKey();
|
||||
const cacheReconciliation = document.getElementById('searchdomainConfigCacheReconciliation').checked;
|
||||
updateSearchdomainConfig(domainKey, { CacheReconciliation: cacheReconciliation});
|
||||
const queryCacheSize = document.getElementById('searchdomainConfigQueryCacheSize').value;
|
||||
updateSearchdomainConfig(domainKey, { CacheReconciliation: cacheReconciliation, QueryCacheSize: queryCacheSize});
|
||||
});
|
||||
|
||||
document
|
||||
@@ -775,8 +792,9 @@
|
||||
document.getElementById('createSearchdomainModal')
|
||||
);
|
||||
const name = document.getElementById('createSearchdomainName').value;
|
||||
const queryCacheSize = document.getElementById('createSearchdomainQueryCacheSize').value;
|
||||
const cacheReconciliation = document.getElementById('createSearchdomainWithCacheReconciliation').checked;
|
||||
const settings = { CacheReconciliation: cacheReconciliation };
|
||||
const settings = { CacheReconciliation: cacheReconciliation, QueryCacheSize: queryCacheSize };
|
||||
// Implement create logic here
|
||||
fetch(`/Searchdomain?searchdomain=${encodeURIComponent(name)}`, {
|
||||
method: 'POST',
|
||||
@@ -1053,6 +1071,7 @@
|
||||
|
||||
let searchdomainConfigPromise = getSearchdomainConfig(getSelectedDomainKey());
|
||||
let configElementCachereconciliation = document.getElementById('searchdomainConfigCacheReconciliation');
|
||||
let configElementCacheSize = document.getElementById('searchdomainConfigQueryCacheSize');
|
||||
|
||||
let cacheUtilizationPromise = getSearchdomainCacheUtilization(getSelectedDomainKey());
|
||||
let databaseUtilizationPromise = getSearchdomainDatabaseUtilization(getSelectedDomainKey());
|
||||
@@ -1097,6 +1116,7 @@
|
||||
searchdomainConfigPromise.then(searchdomainConfig => {
|
||||
if (searchdomainConfig != null && searchdomainConfig.Settings != null)
|
||||
{
|
||||
configElementCacheSize.value = searchdomainConfig.Settings.QueryCacheSize;
|
||||
configElementCachereconciliation.checked = searchdomainConfig.Settings.CacheReconciliation;
|
||||
configElementCachereconciliation.disabled = false;
|
||||
} else {
|
||||
@@ -1106,10 +1126,10 @@
|
||||
}
|
||||
});
|
||||
cacheUtilizationPromise.then(cacheUtilization => {
|
||||
if (cacheUtilization != null && cacheUtilization.QueryCacheSizeBytes != null)
|
||||
if (cacheUtilization != null && cacheUtilization.SizeBytes != null)
|
||||
{
|
||||
document.querySelector('#cacheUtilization').innerText =
|
||||
`${NumberOfBytesAsHumanReadable(cacheUtilization.QueryCacheSizeBytes)}`;
|
||||
`${NumberOfBytesAsHumanReadable(cacheUtilization.SizeBytes)}`;
|
||||
} else {
|
||||
showToast("@T["Unable to fetch searchdomain cache utilization"]", "danger");
|
||||
console.error('Failed to fetch searchdomain cache utilization');
|
||||
|
||||
Reference in New Issue
Block a user