From 5e7261b6aa5d7eb496b9e277815e7e43a0499164 Mon Sep 17 00:00:00 2001 From: uleus Date: Thu, 4 Feb 2021 16:42:30 +0100 Subject: [PATCH] search impreovements --- .../Mapping/SearchableBaseItem.cs | 2 +- .../IElasticClientFactoryService.cs | 2 +- .../{Search => Searching}/SearchService.cs | 83 ++++++++++--------- .../SimpleSearchRequest.cs | 3 +- .../SimpleSerachResponse.cs | 4 +- .../Search.IndexData.Exe/DataProvider.cs | 6 +- .../Controllers/SearchController.cs | 2 +- .../Services/ElasticClientFactoryService.cs | 2 +- Elasticsearch/Search.WebAPI.Exe/Startup.cs | 8 +- 9 files changed, 54 insertions(+), 58 deletions(-) rename Elasticsearch/Search.Elasticsearch/{Search => Searching}/IElasticClientFactoryService.cs (75%) rename Elasticsearch/Search.Elasticsearch/{Search => Searching}/SearchService.cs (70%) rename Elasticsearch/Search.Elasticsearch/{Search => Searching}/SimpleSearchRequest.cs (91%) rename Elasticsearch/Search.Elasticsearch/{Search => Searching}/SimpleSerachResponse.cs (77%) diff --git a/Elasticsearch/Search.Elasticsearch/Mapping/SearchableBaseItem.cs b/Elasticsearch/Search.Elasticsearch/Mapping/SearchableBaseItem.cs index 99f23ff..d79d95f 100644 --- a/Elasticsearch/Search.Elasticsearch/Mapping/SearchableBaseItem.cs +++ b/Elasticsearch/Search.Elasticsearch/Mapping/SearchableBaseItem.cs @@ -13,7 +13,7 @@ public class SearchableBaseItem [Text(Analyzer = "autocomplete", SearchAnalyzer = "autocomplete_search", Name = nameof(Name))] public string Name { get; set; } - [Keyword(Name = nameof(State))] + [Text(Name = nameof(State))] public string State { get; set; } //multifieds : mapping in code diff --git a/Elasticsearch/Search.Elasticsearch/Search/IElasticClientFactoryService.cs b/Elasticsearch/Search.Elasticsearch/Searching/IElasticClientFactoryService.cs similarity index 75% rename from Elasticsearch/Search.Elasticsearch/Search/IElasticClientFactoryService.cs rename to Elasticsearch/Search.Elasticsearch/Searching/IElasticClientFactoryService.cs index 7c8e71c..98883da 100644 --- a/Elasticsearch/Search.Elasticsearch/Search/IElasticClientFactoryService.cs +++ b/Elasticsearch/Search.Elasticsearch/Searching/IElasticClientFactoryService.cs @@ -1,6 +1,6 @@ using Nest; -namespace Search.Elasticsearch.Search +namespace Search.Elasticsearch.Searching { public interface IElasticClientFactoryService { diff --git a/Elasticsearch/Search.Elasticsearch/Search/SearchService.cs b/Elasticsearch/Search.Elasticsearch/Searching/SearchService.cs similarity index 70% rename from Elasticsearch/Search.Elasticsearch/Search/SearchService.cs rename to Elasticsearch/Search.Elasticsearch/Searching/SearchService.cs index 6145017..dc24483 100644 --- a/Elasticsearch/Search.Elasticsearch/Search/SearchService.cs +++ b/Elasticsearch/Search.Elasticsearch/Searching/SearchService.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace Search.Elasticsearch.Search +namespace Search.Elasticsearch.Searching { public interface ISearchService { @@ -23,25 +23,7 @@ public SearchService(IElasticClientFactoryService aElasticClientFactoryService) public async Task Search(SimpleSearchRequest aSearchRequest) { - BoolQuery filterQuery = new BoolQuery(); - if (!string.IsNullOrEmpty(aSearchRequest.MarketFilterQuery)) - { - //we assume that: - // 1: the MarketFilterQuery is in fromat Market1,Market2,Market3 e.g. Austin, San Paulo - // 2: the market names are coming from predefined table, so no spelling mistakes, no autocompletition - // 3: keyword field, and keyword_list_serach analyzer are created with the index - var filterQueryParts = new List(); - filterQueryParts.Add( - new MatchQuery() - { - Field = "Market.keyword", - Query = aSearchRequest.MarketFilterQuery,//.ToLower(), - Analyzer = "keyword_list_serach" - } - ); - - filterQuery.Filter = filterQueryParts; - } + BoolQuery filterQuery = BuildMarketFilterQuery(aSearchRequest.MarketFilterQuery); //check the API to be able to get the specific SearchableBaseItem derived types (something similar to ConcreteTypeSelector?) //for now we use JsonObject and convert it to specific object base on the "TypeName" @@ -49,19 +31,21 @@ public async Task Search(SimpleSearchRequest aSearchReques var results = await _client.SearchAsync(s => s .Size(aSearchRequest.PageSize) .Skip(aSearchRequest.PageStartIndex) - .Index(Indices.Index(aSearchRequest.Indices)) + .Index(Indices.Index(aSearchRequest.Indices)) .Query(q => q .Bool(b => b .Should( - // for City and Market a 'phrase' field is crated, which allowes - // to better place the item in result when the city/market was put in the AllStringFiledsQuery + // for City and Market a 'phrase' field is created, which allowes + // to better place the item in result when the city/market was put as the AllStringFiledsQuery + // e.g. if someone put the AllStringFiledsQuery="San Francisco" ... + // but this match will not work in case of putting the AllStringFiledsQuery="San Francisco properties" bs => bs.MatchPhrase(x => x .Query(aSearchRequest.AllStringFiledsQuery.ToLower()) .Field("City.phrase") ), bs => bs.MatchPhrase(x => x .Query(aSearchRequest.AllStringFiledsQuery.ToLower()) - .Field("Market.phrase") + .Field("Market.phrase") ) ) .Must( @@ -79,17 +63,15 @@ public async Task Search(SimpleSearchRequest aSearchReques .Field($"{nameof(SearchablePropertyItem.FormerName)}") .Field($"{nameof(SearchablePropertyItem.StreetAddres)}") .Field($"{nameof(SearchablePropertyItem.City)}") - ) + ) .Fuzziness(Fuzziness.Auto) ), bs => filterQuery ) - ) + ) ) ); - - return new SimpleSerachResponse() { TotalItems = results.Total, @@ -97,10 +79,33 @@ public async Task Search(SimpleSearchRequest aSearchReques }; } + //we assume that: + // 1: the MarketFilterQuery is in fromat Market1,Market2,Market3 e.g. Austin, San Paulo + // 2: the market names are coming from predefined table, so no spelling mistakes, no autocompletition + // 3: keyword field, and keyword_list_serach analyzer are created with the index + private BoolQuery BuildMarketFilterQuery(string aMarket) + { + BoolQuery filterQuery = new BoolQuery(); + if (!string.IsNullOrEmpty(aMarket)) + { + var filterQueryParts = new List(); + filterQueryParts.Add( + new MatchQuery() + { + Field = "Market.keyword", + Query = aMarket, + Analyzer = "keyword_list_serach" + } + ); + + filterQuery.Filter = filterQueryParts; + } + + return filterQuery; + } private List ConvertResults(ISearchResponse aSerachResponse) - { - + { List ret = new List(); foreach (var item in aSerachResponse.Documents) @@ -111,21 +116,21 @@ private List ConvertResults(ISearchResponse aSer ret.Add(new SearchableManagementItem() { Id = int.Parse(item["Id"].ToString()), - Name = (string)item["Name"], - State = (string)item["State"], - Market = (string)item["Market"] + Name = item.ContainsKey("Name") ? item["Name"].ToString() : "not exist", + State = item.ContainsKey("State") ? item["State"].ToString() : "not exist", + Market = item.ContainsKey("Market") ? item["Market"].ToString() : "not exist", }); break; case "searchablepropertyitem": ret.Add(new SearchablePropertyItem() { Id = int.Parse(item["Id"].ToString()), - Name = item["Name"].ToString(), - State = item["State"].ToString(), - Market = item["Market"].ToString(), - FormerName = item.ContainsKey("FormerName") ? item["FormerName"].ToString() : "", - StreetAddres = item["StreetAddres"].ToString(), - City = (string)item["City"].ToString(), + Name = item.ContainsKey("Name") ? item["Name"].ToString(): "not exist", + State = item.ContainsKey("State") ? item["State"].ToString(): "not exist", + Market = item.ContainsKey("Market") ? item["Market"].ToString(): "not exist", + FormerName = item.ContainsKey("FormerName") ? item["FormerName"].ToString() : "not exist", + StreetAddres = item.ContainsKey("StreetAddres") ? item["StreetAddres"].ToString() : "not exist", + City = item.ContainsKey("City") ? (string)item["City"].ToString() : "not exist", //Lat = (float) item["lat"], //Lng = (float) item["lng"] }); diff --git a/Elasticsearch/Search.Elasticsearch/Search/SimpleSearchRequest.cs b/Elasticsearch/Search.Elasticsearch/Searching/SimpleSearchRequest.cs similarity index 91% rename from Elasticsearch/Search.Elasticsearch/Search/SimpleSearchRequest.cs rename to Elasticsearch/Search.Elasticsearch/Searching/SimpleSearchRequest.cs index 9fa75b1..b4110ab 100644 --- a/Elasticsearch/Search.Elasticsearch/Search/SimpleSearchRequest.cs +++ b/Elasticsearch/Search.Elasticsearch/Searching/SimpleSearchRequest.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -namespace Search.Elasticsearch.Search +namespace Search.Elasticsearch.Searching { - public class SimpleSearchRequest { public List Indices { get; set; } diff --git a/Elasticsearch/Search.Elasticsearch/Search/SimpleSerachResponse.cs b/Elasticsearch/Search.Elasticsearch/Searching/SimpleSerachResponse.cs similarity index 77% rename from Elasticsearch/Search.Elasticsearch/Search/SimpleSerachResponse.cs rename to Elasticsearch/Search.Elasticsearch/Searching/SimpleSerachResponse.cs index ceac312..237cfc7 100644 --- a/Elasticsearch/Search.Elasticsearch/Search/SimpleSerachResponse.cs +++ b/Elasticsearch/Search.Elasticsearch/Searching/SimpleSerachResponse.cs @@ -1,9 +1,7 @@ using Search.Elasticsearch.Mapping; -using System; using System.Collections.Generic; -using System.Text; -namespace Search.Elasticsearch.Search +namespace Search.Elasticsearch.Searching { public class SimpleSerachResponse { diff --git a/Elasticsearch/Search.IndexData.Exe/DataProvider.cs b/Elasticsearch/Search.IndexData.Exe/DataProvider.cs index b67a359..8854f0e 100644 --- a/Elasticsearch/Search.IndexData.Exe/DataProvider.cs +++ b/Elasticsearch/Search.IndexData.Exe/DataProvider.cs @@ -23,13 +23,13 @@ public DataProvider() Market="Austin", State ="GS", StreetAddres = "3549 Curry Lane", - City = "San Francesco" + City = "San Francisco" }, new SearchablePropertyItem() { Id = 2, - Name ="Forest at Columbia AAAA San in Paulo", - StreetAddres = "1000 Merrick Ferry Road San in Paulo", + Name ="Forest at Columbia AAAA San in Paulo San Francisco", + StreetAddres = "1000 Merrick Ferry Road San Francisco", Market="Austin", State ="GS", City = "San in Paulo" diff --git a/Elasticsearch/Search.WebAPI.Exe/Controllers/SearchController.cs b/Elasticsearch/Search.WebAPI.Exe/Controllers/SearchController.cs index 288110c..d036b73 100644 --- a/Elasticsearch/Search.WebAPI.Exe/Controllers/SearchController.cs +++ b/Elasticsearch/Search.WebAPI.Exe/Controllers/SearchController.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using Search.Elasticsearch; using Search.Elasticsearch.Mapping; -using Search.Elasticsearch.Search; +using Search.Elasticsearch.Searching; using Search.WebAPI.Exe.Dto; namespace Search.WebAPI.Exe.Controllers diff --git a/Elasticsearch/Search.WebAPI.Exe/Services/ElasticClientFactoryService.cs b/Elasticsearch/Search.WebAPI.Exe/Services/ElasticClientFactoryService.cs index 20e4ae9..3adf02b 100644 --- a/Elasticsearch/Search.WebAPI.Exe/Services/ElasticClientFactoryService.cs +++ b/Elasticsearch/Search.WebAPI.Exe/Services/ElasticClientFactoryService.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Configuration; using Nest; -using Search.Elasticsearch.Search; +using Search.Elasticsearch.Searching; using System; namespace Search.WebAPI.Exe.Services diff --git a/Elasticsearch/Search.WebAPI.Exe/Startup.cs b/Elasticsearch/Search.WebAPI.Exe/Startup.cs index 7cda9fb..db5ce1f 100644 --- a/Elasticsearch/Search.WebAPI.Exe/Startup.cs +++ b/Elasticsearch/Search.WebAPI.Exe/Startup.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Search.Elasticsearch.Search; +using Search.Elasticsearch.Searching; using Search.WebAPI.Exe.Services; namespace Search.WebAPI.Exe