Skip to content

Commit

Permalink
Merge pull request #995 from IgorAlymov/SITKO-CORE-T-20
Browse files Browse the repository at this point in the history
feat: added Wildcard searching
  • Loading branch information
pogromistik authored Jul 29, 2024
2 parents 7c7e174 + 89af8b2 commit defd56f
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/Sitko.Core.Search.ElasticSearch/ElasticSearcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public async Task<long> CountAsync(string indexName, string term, CancellationTo
return resultsCount.Count;
}

public async Task<TSearchModel[]> SearchAsync(string indexName, string term, int limit,
public async Task<TSearchModel[]> SearchAsync(string indexName, string term, int limit, SearchType searchType,
CancellationToken cancellationToken = default)
{
indexName = $"{Options.Prefix}_{indexName}";
Expand Down
20 changes: 15 additions & 5 deletions src/Sitko.Core.Search.OpenSearch/OpenSearchSearcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ public async Task<long> CountAsync(string indexName, string term, CancellationTo
}

public async Task<TSearchModel[]> SearchAsync(string indexName, string term, int limit,
CancellationToken cancellationToken = default)
SearchType searchType, CancellationToken cancellationToken = default)
{
indexName = $"{Options.Prefix}_{indexName}";
var results = await GetClient()
.SearchAsync<TSearchModel>(x => GetSearchRequest(x, indexName, term, limit), cancellationToken);
.SearchAsync<TSearchModel>(x => GetSearchRequest(x, indexName, term, searchType, limit), cancellationToken);
if (results.ServerError != null)
{
logger.LogError("Error while searching in {IndexName}: {ErrorText}", indexName, results.ServerError);
Expand Down Expand Up @@ -240,11 +240,21 @@ private static string GetSearchText(string? term)
}

private static SearchDescriptor<TSearchModel> GetSearchRequest(SearchDescriptor<TSearchModel> descriptor,
string indexName, string term, int limit = 0)
string indexName, string term, SearchType searchType, int limit = 0)
{
var names = GetSearchText(term);
return descriptor.Query(q => q.QueryString(qs => qs.Query(names)))
.Sort(s => s.Descending(SortSpecialField.Score).Descending(model => model.Date))
switch (searchType)
{
case SearchType.Morphology:
descriptor.Query(q => q.QueryString(qs => qs.Query(names)));
break;
case SearchType.Wildcard:
descriptor.Query(q =>
q.QueryString(qs => qs.Query($"*{names}*").AnalyzeWildcard()));
break;
}

return descriptor.Sort(s => s.Descending(SortSpecialField.Score).Descending(model => model.Date))
.Size(limit > 0 ? limit : 20)
.Index(indexName.ToLowerInvariant());
}
Expand Down
8 changes: 4 additions & 4 deletions src/Sitko.Core.Search/BaseSearchProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ public Task<long> CountAsync(string term, CancellationToken cancellationToken =
public Task InitAsync(CancellationToken cancellationToken = default) =>
searcher.InitAsync(IndexName, cancellationToken);

public async Task<T[]> SearchAsync(string term, int limit, CancellationToken cancellationToken = default)
public async Task<T[]> SearchAsync(string term, int limit, SearchType searchType, CancellationToken cancellationToken = default)
{
var result = await searcher.SearchAsync(IndexName, term, limit, cancellationToken);
var result = await searcher.SearchAsync(IndexName, term, limit, searchType, cancellationToken);
return await LoadEntities(result, cancellationToken);
}

public async Task<TEntityPk[]> GetIdsAsync(string term, int limit,
public async Task<TEntityPk[]> GetIdsAsync(string term, int limit, SearchType searchType,
CancellationToken cancellationToken = default)
{
var result = await searcher.SearchAsync(IndexName, term, limit, cancellationToken);
var result = await searcher.SearchAsync(IndexName, term, limit, searchType, cancellationToken);
return result.Select(m => ParseId(m.Id)).ToArray();
}

Expand Down
4 changes: 2 additions & 2 deletions src/Sitko.Core.Search/ISearchProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public interface ISearchProvider

public interface ISearchProvider<TEntity, TEntityPk> : ISearchProvider where TEntity : class
{
Task<TEntity[]> SearchAsync(string term, int limit, CancellationToken cancellationToken = default);
Task<TEntityPk[]> GetIdsAsync(string term, int limit, CancellationToken cancellationToken = default);
Task<TEntity[]> SearchAsync(string term, int limit, SearchType searchType, CancellationToken cancellationToken = default);
Task<TEntityPk[]> GetIdsAsync(string term, int limit, SearchType searchType, CancellationToken cancellationToken = default);
Task<TEntity[]> GetSimilarAsync(string id, int limit, CancellationToken cancellationToken = default);

Task<TEntityPk[]> GetSimilarIdsAsync(string id, int limit,
Expand Down
2 changes: 1 addition & 1 deletion src/Sitko.Core.Search/ISearcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Task<bool> DeleteAsync(string indexName, IEnumerable<T> searchModels,

Task<bool> DeleteAsync(string indexName, CancellationToken cancellationToken = default);
Task<long> CountAsync(string indexName, string term, CancellationToken cancellationToken = default);
Task<T[]> SearchAsync(string indexName, string term, int limit, CancellationToken cancellationToken = default);
Task<T[]> SearchAsync(string indexName, string term, int limit, SearchType searchType, CancellationToken cancellationToken = default);

Task<T[]> GetSimilarAsync(string indexName, string id, int limit,
CancellationToken cancellationToken = default);
Expand Down
7 changes: 7 additions & 0 deletions src/Sitko.Core.Search/SearchType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Sitko.Core.Search;

public enum SearchType
{
Wildcard = 0,
Morphology = 1
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async Task Search()

await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));
var result = await searchProvider.SearchAsync("samsung", 10);
var result = await searchProvider.SearchAsync("samsung", 10, SearchType.Morphology);
Assert.Equal(provider.Models.Count, result.Length);
Assert.Equal(barModel.Id, result.First().Id);
}
Expand Down
60 changes: 57 additions & 3 deletions tests/Sitko.Core.Search.OpenSearch.Tests/OpenSearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task SearchAsync()

await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));
var result = await searchProvider.SearchAsync("samsung", 10);
var result = await searchProvider.SearchAsync("samsung", 10, SearchType.Morphology);
result.Length.Should().Be(provider.Models.Count);
result.First().Id.Should().Be(barModel.Id);
}
Expand Down Expand Up @@ -69,7 +69,7 @@ public async Task MorphologyRusTestAsync(int foundDocs, string searchText)
await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));

var result = await searchProvider.SearchAsync(searchText, 10);
var result = await searchProvider.SearchAsync(searchText, 10, SearchType.Morphology);
result.Length.Should().Be(foundDocs);
}

Expand All @@ -92,9 +92,63 @@ public async Task MorphologyEngTestAsync()
await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));

var result = await searchProvider.SearchAsync("walked", 10);
var result = await searchProvider.SearchAsync("walked", 10, SearchType.Morphology);
result.Length.Should().Be(3);
}

[Theory(DisplayName = "PartialSearchEngTest")]
[InlineData(1, "74")]
[InlineData(1, "kol")]
[InlineData(1, "kolesa")]
[InlineData(1, "74ko")]
public async Task PartialSearchEngTestAsync(int foundDocs, string searchText)
{
var scope = await GetScopeAsync();
var provider = scope.GetService<TestModelProvider>();
var searchProvider = scope.GetService<ISearchProvider<TestModel, Guid>>();
await searchProvider.DeleteIndexAsync();
await searchProvider.InitAsync();

var firstModel = new TestModel { Title = "MMI", Description = "74kolesa", Url = "mmicentre" };
var secondModel = new TestModel { Title = "MMI", Description = "walked", Url = "mmicentre" };
var thirdModel =
new TestModel { Title = "MMI", Description = "walking", Url = "mmicentre" };
var forthModel = new TestModel { Title = "MMI", Description = "MMI", Url = "mmicentre" };
provider.AddModel(firstModel).AddModel(secondModel).AddModel(thirdModel).AddModel(forthModel);

await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));

var result = await searchProvider.SearchAsync(searchText, 10, SearchType.Wildcard);
result.Length.Should().Be(foundDocs);
}

[Theory(DisplayName = "PartialSearchRusTest")]
[InlineData(1, "кол")]
[InlineData(1, "74кол")]
[InlineData(1, "74колес")]
[InlineData(1, "74ко")]
public async Task PartialSearchRusTestAsync(int foundDocs, string searchText)
{
var scope = await GetScopeAsync();
var provider = scope.GetService<TestModelProvider>();
var searchProvider = scope.GetService<ISearchProvider<TestModel, Guid>>();
await searchProvider.DeleteIndexAsync();
await searchProvider.InitAsync();

var firstModel = new TestModel { Title = "MMI", Description = "74колеса", Url = "mmicentre" };
var secondModel = new TestModel { Title = "MMI", Description = "walked", Url = "mmicentre" };
var thirdModel =
new TestModel { Title = "MMI", Description = "walking", Url = "mmicentre" };
var forthModel = new TestModel { Title = "MMI", Description = "MMI", Url = "mmicentre" };
provider.AddModel(firstModel).AddModel(secondModel).AddModel(thirdModel).AddModel(forthModel);

await searchProvider.AddOrUpdateEntitiesAsync(provider.Models.ToArray());
await Task.Delay(TimeSpan.FromSeconds(5));

var result = await searchProvider.SearchAsync(searchText, 10, SearchType.Wildcard);
result.Length.Should().Be(foundDocs);
}
}

public class OpenSearchTestScope : BaseTestScope
Expand Down

0 comments on commit defd56f

Please sign in to comment.