From 271479cbe8159ffc83d76f62e729cbfac9f646a3 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:20:12 +0000 Subject: [PATCH 01/11] Add event for CreatingIndex --- .../AzureSearchServiceClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs index 9c25f5f..0cf2c59 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs @@ -35,6 +35,8 @@ private string SessionFile(string sessionId) return Path.Combine(path, sessionId + ".json"); } + public event EventHandler CreatingIndex; + public string DropCreateIndex() { var serviceClient = GetClient(); @@ -56,6 +58,7 @@ public string DropCreateIndex() try { + CreatingIndex?.Invoke(this, definition); serviceClient.Indexes.Create(definition); } catch (Exception ex) From 44d8f3c7164c0eb11fd0e8c4ef6e388ab2e14d1b Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:22:43 +0000 Subject: [PATCH 02/11] Sorted umbraco fields --- .../AzureSearchServiceClient.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs index 0cf2c59..6bd16f8 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs @@ -506,10 +506,10 @@ private void SetCustomFieldParsers(AzureSearchConfig azureSearchConfig) public Field[] GetStandardUmbracoFields() { // Key field has to be a string.... - return new[] - { - new Field("Id", DataType.String) { IsKey = true, IsFilterable = true, IsSortable = true }, + var key = new Field("Id", DataType.String) { IsKey = true, IsFilterable = true, IsSortable = true }; + var fields = new [] + { new Field("Name", DataType.String) { IsFilterable = true, IsSortable = true, IsSearchable = true, IsRetrievable = true}, new Field("Key", DataType.String) { IsSearchable = true, IsRetrievable = true}, @@ -540,6 +540,11 @@ public Field[] GetStandardUmbracoFields() new Field("WriterId", DataType.Int32) { IsSortable = true, IsFacetable = true }, new Field("CreatorId", DataType.Int32) { IsSortable = true, IsFacetable = true } }; + + var sorted = new List(fields.OrderBy(f => f.Name)); + sorted.Insert(0, key); + + return sorted.ToArray(); } } } From 310d9c3b8f280fc8b496b1c59c8a338356ab126b Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:24:21 +0000 Subject: [PATCH 03/11] Add search term highlighting --- .../AzureSearchClient.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs index 5f0a02b..322f0be 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs @@ -104,6 +104,16 @@ private ISearchResult Results(SearchParameters sp) var client = GetClient(); var config = GetConfiguration(); + sp.HighlightFields = new List(); + + foreach (var field in config.SearchFields.Where(f => f.IsSearchable)) + { + sp.HighlightFields.Add(field.Name); + } + + sp.HighlightPreTag = ""; + sp.HighlightPostTag = ""; + ISearchIndexClient indexClient = client.Indexes.GetClient(config.IndexName); var response = indexClient.Documents.Search(_searchTerm, sp); @@ -111,7 +121,10 @@ private ISearchResult Results(SearchParameters sp) foreach (var result in response.Results) { - results.Content.Add(FromDocument(result.Document, result.Score)); + var doc = FromDocument(result.Document, result.Score); + + doc.Properties.Add("__match", result.Highlights); + results.Content.Add(doc); } if (response.Facets != null) From 4ff783bb171ec17acd3b3178c0948a8f7a1e67a7 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:27:17 +0000 Subject: [PATCH 04/11] Add searchablepath --- .../AzureSearchServiceClient.cs | 2 ++ .../Interfaces/ISearchContent.cs | 1 + .../Models/SearchContent.cs | 1 + 3 files changed, 4 insertions(+) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs index 6bd16f8..29c4a4e 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchServiceClient.cs @@ -371,6 +371,7 @@ private Document GetDocumentToIndex(IContentBase content, SearchField[] searchFi {"Name", content.Name}, {"SortOrder", content.SortOrder}, {"Level", content.Level}, + {"SearchablePath", content.Path.TrimStart('-') }, {"Path", content.Path.Split(',') }, {"ParentId", content.ParentId}, {"UpdateDate", content.UpdateDate}, @@ -523,6 +524,7 @@ public Field[] GetStandardUmbracoFields() new Field("Published", DataType.Boolean) { IsFilterable = true, IsFacetable = true }, new Field("Trashed", DataType.Boolean) { IsFilterable = true, IsFacetable = true }, + new Field("SearchablePath", DataType.String) { IsSearchable = true, IsFilterable = true}, new Field("Path", DataType.Collection(DataType.String)) { IsSearchable = true, IsFilterable = true }, new Field("Template", DataType.String) { IsSearchable = true, IsFacetable = true }, new Field("Icon", DataType.String) { IsSearchable = true, IsFacetable = true }, diff --git a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/ISearchContent.cs b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/ISearchContent.cs index d1808a4..1526670 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/ISearchContent.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/ISearchContent.cs @@ -22,6 +22,7 @@ public interface ISearchContent int Level { get; set; } string[] Path { get; set; } + string SearchablePath { get; set; } int ParentId { get; set; } diff --git a/Moriyama.AzureSearch.Umbraco.Application/Models/SearchContent.cs b/Moriyama.AzureSearch.Umbraco.Application/Models/SearchContent.cs index bcdeb24..1445ca3 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Models/SearchContent.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Models/SearchContent.cs @@ -18,6 +18,7 @@ public class SearchContent : BaseContent, ISearchContent public bool IsMember { get; set; } public string[] Path { get; set; } + public string SearchablePath { get; set; } public IDictionary Properties { get; set; } } From 7dae843f93f4988b5e7a810c8c82bc6b154a38a2 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:28:28 +0000 Subject: [PATCH 05/11] Add search.in and filter support --- .../AzureSearchClient.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs index 322f0be..5a32a70 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs @@ -279,6 +279,12 @@ public IAzureSearchClient Filter(string field, bool value) return this; } + public IAzureSearchClient Filter(string filter) + { + _filters.Add(filter); + return this; + } + public IAzureSearchClient Facet(string facet) { _facets.Add(facet); @@ -295,6 +301,12 @@ public IAzureSearchClient Facets(string[] facets) return this; } + public IAzureSearchClient SearchIn(string field, IEnumerable values) + { + _filters.Add($"search.in({field}, '{string.Join(",", values)}')"); + return this; + } + public IAzureSearchClient Any(string field) { _filters.Add(string.Format("{0}/any()", field)); From ea2c6487cb32a17bc2f99379e70aa802ffa4c8ec Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:29:06 +0000 Subject: [PATCH 06/11] Add search.in and filter support --- .../Interfaces/IAzureSearchClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs index fc00475..af40451 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs @@ -26,6 +26,7 @@ public interface IAzureSearchClient IAzureSearchClient Filter(string field, string[] values); IAzureSearchClient Filter(string field, int value); IAzureSearchClient Filter(string field, bool value); + IAzureSearchClient Filter(string filter); IAzureSearchClient DateRange(string field, DateTime? start, DateTime? end); @@ -39,6 +40,8 @@ public interface IAzureSearchClient IAzureSearchClient Any(string field); + IAzureSearchClient SearchIn(string field, IEnumerable values); + IList Suggest(string value, int count, bool fuzzy = true); } } From 73b154c7456f649c7e41956483a0797f44803dca Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:30:44 +0000 Subject: [PATCH 07/11] Add support for full query syntax --- .../AzureSearchClient.cs | 7 +++++++ .../Interfaces/IAzureSearchClient.cs | 1 + 2 files changed, 8 insertions(+) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs index 5a32a70..3691316 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs @@ -29,6 +29,7 @@ public IList Filters private string _searchTerm = "*"; private IList _orderBy; private IList _facets; + private QueryType _queryType = QueryType.Simple; private bool _content; private bool _media; @@ -89,6 +90,7 @@ private SearchParameters GetSearchParameters() sp.Skip = (_page - 1) * _pageSize; sp.OrderBy = _orderBy; sp.Facets = _facets; + sp.QueryType = _queryType; return sp; } @@ -421,5 +423,10 @@ public IList Suggest(string value, int count, bool fuzzy = true) return indexClient.Documents.Suggest(value, "sg", sp).Results; } + + public void SetQueryType(QueryType type) + { + _queryType = type; + } } } diff --git a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs index af40451..e59bd01 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs @@ -43,5 +43,6 @@ public interface IAzureSearchClient IAzureSearchClient SearchIn(string field, IEnumerable values); IList Suggest(string value, int count, bool fuzzy = true); + void SetQueryType(QueryType type); } } From 839804661c6d934f3d2b83f388260c3b3147dd25 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 02:32:21 +0000 Subject: [PATCH 08/11] add support for custom search params --- Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs | 4 ++-- .../Interfaces/IAzureSearchClient.cs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs index 3691316..a7f3bb3 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/AzureSearchClient.cs @@ -65,7 +65,7 @@ public IAzureSearchClient DocumentTypes(IEnumerable typeAliases) return this; } - private SearchParameters GetSearchParameters() + public SearchParameters GetSearchParameters() { var sp = new SearchParameters(); @@ -101,7 +101,7 @@ public ISearchResult Results() return Results(sp); } - private ISearchResult Results(SearchParameters sp) + public ISearchResult Results(SearchParameters sp) { var client = GetClient(); var config = GetConfiguration(); diff --git a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs index e59bd01..5425590 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Interfaces/IAzureSearchClient.cs @@ -9,6 +9,8 @@ public interface IAzureSearchClient IList Filters { get; set; } ISearchResult Results(); + ISearchResult Results(SearchParameters sp); + SearchParameters GetSearchParameters(); IAzureSearchClient Term(string query); IAzureSearchClient DocumentType(string typeAlias); From 9100d4baa43faefe7438a4ba02ab54e3ff4d6cb8 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 00:59:05 +0000 Subject: [PATCH 09/11] Add code to copy fields from examine config --- .../Extensions/SearchFieldsExtensions.cs | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Moriyama.AzureSearch.Umbraco.Application/Extensions/SearchFieldsExtensions.cs b/Moriyama.AzureSearch.Umbraco.Application/Extensions/SearchFieldsExtensions.cs index 555373e..f8a0d61 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Extensions/SearchFieldsExtensions.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Extensions/SearchFieldsExtensions.cs @@ -1,10 +1,51 @@ -using Microsoft.Azure.Search.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using Examine.LuceneEngine.Config; +using Microsoft.Azure.Search.Models; using Moriyama.AzureSearch.Umbraco.Application.Models; +using Umbraco.Core; namespace Moriyama.AzureSearch.Umbraco.Application.Extensions { public static class SearchFieldsExtensions { + public static void CopyFieldsFromExamineIndexSet(string examineSetName) + { + var indexSet = IndexSets.Instance.Sets[examineSetName]; + if (indexSet != null) + { + var searchClient = AzureSearchContext.Instance.SearchIndexClient; + var config = searchClient.GetConfiguration(); + var configuredFields = config.SearchFields?.ToDictionary(f => f.Name); + + foreach (IndexField userField in indexSet.IndexUserFields) + { + SearchField field; + if (!configuredFields.TryGetValue(userField.Name, out field)) + { + field = new SearchField(); + configuredFields.Add(userField.Name, field); + } + + field.Name = userField.Name; + field.Type = userField.Type; // TODO: test type mapping + field.IsSortable = userField.EnableSorting; + field.IsSearchable = true; + } + + try + { + config.SearchFields = configuredFields.Select(f => f.Value).ToArray(); + searchClient.SaveConfiguration(config); + } + catch (Exception ex) + { + + } + } + } + public static Field ToAzureField(this SearchField field) { var t = DataType.String; From 7e280b2e2bedcdfec834098e1664acadff9f349f Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 10 Jan 2018 01:01:04 +0000 Subject: [PATCH 10/11] Add examine searcher support --- .../Examine/AzureExamineSearchResults.cs | 135 ++++++++++++++++++ .../Examine/DummyUmbracoExamineSearcher.cs | 91 ++++++++---- .../Examine/LuceneQuery.cs | 11 ++ ...ama.AzureSearch.Umbraco.Application.csproj | 2 + 4 files changed, 208 insertions(+), 31 deletions(-) create mode 100644 Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs create mode 100644 Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs new file mode 100644 index 0000000..147bc3c --- /dev/null +++ b/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Examine; +using System.Linq; +using Moriyama.AzureSearch.Umbraco.Application.Interfaces; +using Newtonsoft.Json; +using Umbraco.Core; +using SearchResult = Examine.SearchResult; + +namespace Moriyama.AzureSearch.Umbraco.Application.Examine +{ + public class AzureExamineSearchResults : ISearchResults + { + public AzureExamineSearchResults(ISearchResult results) + { + _azureResults = results; + + if (results != null) + TotalItemCount = results.Count; + } + + private readonly ISearchResult _azureResults; + private int _position; + + public IEnumerator GetEnumerator() + { + using (var iterator = _azureResults?.Content?.GetEnumerator()) + { + while (iterator != null && iterator.MoveNext()) + { + yield return Convert(iterator.Current); + } + } + } + + private SearchResult Convert(ISearchContent azureResult) + { + if (azureResult == null) return null; + + var result = new SearchResult + { + DocId = _position, + Id = azureResult.Id, + Score = (float) azureResult.Score, + }; + + if (result.Fields == null) return result; + + var indexType = "content"; + if (azureResult.IsMedia) + { + indexType = "media"; + } + + if (azureResult.IsMember) + { + indexType = "member"; + } + + result.Fields.Add("__IndexType", indexType); + result.Fields.Add("__NodeId", azureResult.Id.ToString()); + result.Fields.Add("__Path", $"-{azureResult.SearchablePath}"); + result.Fields.Add("__NodeTypeAlias", azureResult.ContentTypeAlias?.ToLower()); + result.Fields.Add("__Key", azureResult.Key); + result.Fields.Add("id", azureResult.Id.ToString()); + result.Fields.Add("nodeName", azureResult.Name); + result.Fields.Add("createDate", azureResult.CreateDate.ToString("yyyyMMddHHmmsss")); + + if (azureResult.Properties == null) return result; + + foreach (var prop in azureResult.Properties) + { + if (prop.Key == null || prop.Value == null) continue; + + result.Fields[prop.Key] = GetPropertyString(prop.Value); + } + + var icon = ""; + object iconObj = null; + if (azureResult.Properties?.TryGetValue("Icon", out iconObj) == true) + { + icon = iconObj.ToString(); + } + + result.Fields.Add("__Icon", icon); + + return result; + } + + private static string GetPropertyString(object value) + { + if (value == null) return string.Empty; + + var type = value.GetType(); + if (type == typeof(string) || !type.IsEnumerable()) + { + return value.ToString(); + } + + switch (value) + { + case IEnumerable enumerable: + var values = enumerable.Select(i => i?.ToString()); + return string.Join(", ", values); + + default: + return JsonConvert.SerializeObject(value); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerable Skip(int skip) + { + _position = skip + 1; + using (var enumerator = GetEnumerator()) + { + while (enumerator.MoveNext()) + { + yield return enumerator.Current; + } + } + } + + public int TotalItemCount + { + get; + } + } +} + diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs index 5a8000c..784d117 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs @@ -1,49 +1,78 @@ -using Examine; +using System; +using System.Collections.Generic; +using Examine; using Examine.SearchCriteria; using System.IO; +using System.Linq; +using Examine.LuceneEngine; +using Examine.LuceneEngine.Config; +using Examine.LuceneEngine.SearchCriteria; +using Umbraco.Web.Models.ContentEditing; using UmbracoExamine; +using Lucene.Net.Search; +using Microsoft.Azure.Search.Models; +using Newtonsoft.Json; +using StackExchange.Profiling; +using Umbraco.Core.Logging; namespace Moriyama.AzureSearch.Umbraco.Application.Examine { - public class DummyUmbracoExamineSearcher : UmbracoExamineSearcher + public partial class DummyUmbracoExamineSearcher : UmbracoExamineSearcher { - public override ISearchResults Search(ISearchCriteria searchParams) + public override ISearchResults Search(ISearchCriteria searchCriteria) { - // Doing this will make Umbraco fallback to the database. - // We could in future implement this to make it come from Azure search. - throw new FileNotFoundException(""); - - //// Video Nasty - //var s = searchParams.ToString(); - //int id = 0; + try + { + if (searchCriteria != null) + { + var client = AzureSearchContext.Instance?.GetSearchClient(); + if (client != null) + { + client.SetQueryType(QueryType.Full); + client.Filter("Published", true); + client.Filter("Trashed", false); - //try - //{ - // s = s.Substring(s.IndexOf("NodeId:") + 7); - // s = s.Substring(0, s.IndexOf(" ")); + var indexSet = IndexSets.Instance?.Sets?[IndexSetName]; + if (indexSet != null) + { + client.Filter(GetExcludedDocTypesFilter(indexSet)); + } + + var query = GetLuceneQuery(searchCriteria); + var azQuery = client.Term(query); + var azureResults = azQuery?.Results(); - // int.TryParse(s, out id); + ISearchResults azureExamineResults = new AzureExamineSearchResults(azureResults); + return azureExamineResults; + } + } + } + catch (Exception ex) + { + LogHelper.Error(GetType(), ex.Message, ex); + } - // if(id > 0) - // { - // var client = AzureSearchContext.Instance; - // var media = client.SearchClient.Media().Filter("Id", id.ToString()).Results(); - - // if(media.Count == 1) - // { - // var mediaItem = media.Content[0]; + // Doing this will make Umbraco fallback to the database. + throw new FileNotFoundException(""); + } - // } - // } + private static string GetLuceneQuery(ISearchCriteria searchCriteria) + { + if (searchCriteria is LuceneSearchCriteria criteria) return criteria.Query?.ToString(); - //} - //catch (Exception ex) - //{ + var criteriaString = searchCriteria?.ToString().Replace("LuceneQuery: (", "LuceneQuery: \"(").Replace(") }", ")\" }"); + var query = JsonConvert.DeserializeObject(criteriaString); + return query?.LuceneQuery; + } - //} + private static string GetExcludedDocTypesFilter(IndexSet indexSet) + { + var excludeDocs = indexSet?.ExcludeNodeTypes?.ToList(); + if (excludeDocs?.Any() == false) return string.Empty; - //throw new FileNotFoundException(""); - + var docNames = excludeDocs?.Select(i => i?.Name) ?? Enumerable.Empty(); + return $"not search.in(ContentTypeAlias, '{string.Join(", ", docNames)}')"; } } } + diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs new file mode 100644 index 0000000..11b9c23 --- /dev/null +++ b/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs @@ -0,0 +1,11 @@ +namespace Moriyama.AzureSearch.Umbraco.Application.Examine +{ + public partial class DummyUmbracoExamineSearcher + { + public class Query + { + public string LuceneQuery {get; set;} + } + } +} + diff --git a/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj b/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj index d02602d..f895037 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj +++ b/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj @@ -279,8 +279,10 @@ + + From 03a10908e2d9d228561c781c255f10fe25cefa73 Mon Sep 17 00:00:00 2001 From: Tom Pipe Date: Wed, 17 Jan 2018 15:15:01 +0000 Subject: [PATCH 11/11] Better handling of extracting the lucene query, and retained backwards compatibility with examine version --- .../Examine/AzureExamineSearchResults.cs | 3 - .../Examine/DummyUmbracoExamineSearcher.cs | 9 +- .../Examine/LuceneQuery.cs | 11 - ...ama.AzureSearch.Umbraco.Application.csproj | 659 +++++++++--------- 4 files changed, 334 insertions(+), 348 deletions(-) delete mode 100644 Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs index 147bc3c..918dccb 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Examine/AzureExamineSearchResults.cs @@ -21,7 +21,6 @@ public AzureExamineSearchResults(ISearchResult results) } private readonly ISearchResult _azureResults; - private int _position; public IEnumerator GetEnumerator() { @@ -40,7 +39,6 @@ private SearchResult Convert(ISearchContent azureResult) var result = new SearchResult { - DocId = _position, Id = azureResult.Id, Score = (float) azureResult.Score, }; @@ -116,7 +114,6 @@ IEnumerator IEnumerable.GetEnumerator() public IEnumerable Skip(int skip) { - _position = skip + 1; using (var enumerator = GetEnumerator()) { while (enumerator.MoveNext()) diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs index 784d117..1c9629c 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs +++ b/Moriyama.AzureSearch.Umbraco.Application/Examine/DummyUmbracoExamineSearcher.cs @@ -4,6 +4,7 @@ using Examine.SearchCriteria; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using Examine.LuceneEngine; using Examine.LuceneEngine.Config; using Examine.LuceneEngine.SearchCriteria; @@ -58,11 +59,11 @@ public override ISearchResults Search(ISearchCriteria searchCriteria) private static string GetLuceneQuery(ISearchCriteria searchCriteria) { - if (searchCriteria is LuceneSearchCriteria criteria) return criteria.Query?.ToString(); + // this line can be used when examine dependency is updated + //if (searchCriteria is LuceneSearchCriteria criteria) return criteria.Query?.ToString(); - var criteriaString = searchCriteria?.ToString().Replace("LuceneQuery: (", "LuceneQuery: \"(").Replace(") }", ")\" }"); - var query = JsonConvert.DeserializeObject(criteriaString); - return query?.LuceneQuery; + var query = Regex.Match(searchCriteria.ToString(), "LuceneQuery: (.*\\)) }"); + return query.Success && query.Groups.Count > 0 ? query.Groups[1].Value : string.Empty;; } private static string GetExcludedDocTypesFilter(IndexSet indexSet) diff --git a/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs b/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs deleted file mode 100644 index 11b9c23..0000000 --- a/Moriyama.AzureSearch.Umbraco.Application/Examine/LuceneQuery.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Moriyama.AzureSearch.Umbraco.Application.Examine -{ - public partial class DummyUmbracoExamineSearcher - { - public class Query - { - public string LuceneQuery {get; set;} - } - } -} - diff --git a/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj b/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj index f895037..2b123b3 100644 --- a/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj +++ b/Moriyama.AzureSearch.Umbraco.Application/Moriyama.AzureSearch.Umbraco.Application.csproj @@ -1,333 +1,332 @@ - - - - - Debug - AnyCPU - {16C2B0B3-A208-4498-96BA-DEE25A49A581} - Library - Properties - Moriyama.AzureSearch.Umbraco.Application - Moriyama.AzureSearch.Umbraco.Application - v4.5.2 - 512 - ..\ + + + + + Debug + AnyCPU + {16C2B0B3-A208-4498-96BA-DEE25A49A581} + Library + Properties + Moriyama.AzureSearch.Umbraco.Application + Moriyama.AzureSearch.Umbraco.Application + v4.5.2 + 512 + ..\ true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll - True - - - ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\businesslogic.dll - True - - - ..\packages\ClientDependency.1.9.1\lib\net45\ClientDependency.Core.dll - True - - - ..\packages\ClientDependency-Mvc5.1.8.0.0\lib\net45\ClientDependency.Core.Mvc.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\cms.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\controls.dll - True - - - ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll - True - - - ..\packages\Examine.0.1.69.0\lib\Examine.dll - True - - - ..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll - True - - - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True - - - ..\packages\ImageProcessor.2.4.4.0\lib\net45\ImageProcessor.dll - True - - - ..\packages\ImageProcessor.Web.4.6.4.0\lib\net45\ImageProcessor.Web.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\interfaces.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\log4net.dll - True - - - ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True - - - ..\packages\Markdown.1.14.4\lib\net45\MarkdownSharp.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\Microsoft.ApplicationBlocks.Data.dll - True - - - ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll - True - - - ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll - True - - - ..\packages\Microsoft.Azure.Search.3.0.4\lib\net452\Microsoft.Azure.Search.dll - - - ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll - True - - - ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - True - - - ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll - True - - - ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll - True - - - ..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll - True - - - ..\packages\Microsoft.Rest.ClientRuntime.2.3.9\lib\net452\Microsoft.Rest.ClientRuntime.dll - - - ..\packages\Microsoft.Rest.ClientRuntime.Azure.3.3.9\lib\net452\Microsoft.Rest.ClientRuntime.Azure.dll - - - ..\packages\Microsoft.Spatial.7.2.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll - - - ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True - - - ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll - True - - - ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - True - - - ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll - True - - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - True - - - ..\packages\semver.1.1.2\lib\net451\Semver.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\SQLCE4Umbraco.dll - True - - - - - - ..\packages\UmbracoCms.Core.7.5.3\lib\System.Data.SqlServerCe.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\System.Data.SqlServerCe.Entity.dll - True - - - - ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll - True - - - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True - - - ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll - True - - - ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll - True - - - ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True - - - ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True - - - ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True - - - - - - - - - ..\packages\UmbracoCms.Core.7.5.3\lib\TidyNet.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\Umbraco.Core.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.DataLayer.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.editorControls.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.MacroEngines.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.providers.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\Umbraco.Web.UI.dll - True - - - ..\packages\UmbracoCms.Core.7.5.3\lib\UmbracoExamine.dll - True - - - ..\packages\UrlRewritingNet.2.0.7\lib\UrlRewritingNet.UrlRewriter.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - - - - - + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll + True + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\businesslogic.dll + True + + + ..\packages\ClientDependency.1.9.1\lib\net45\ClientDependency.Core.dll + True + + + ..\packages\ClientDependency-Mvc5.1.8.0.0\lib\net45\ClientDependency.Core.Mvc.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\cms.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\controls.dll + True + + + ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll + True + + + ..\packages\Examine.0.1.69.0\lib\Examine.dll + True + + + ..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll + True + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + + + ..\packages\ImageProcessor.2.4.4.0\lib\net45\ImageProcessor.dll + True + + + ..\packages\ImageProcessor.Web.4.6.4.0\lib\net45\ImageProcessor.Web.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\interfaces.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\log4net.dll + True + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + True + + + ..\packages\Markdown.1.14.4\lib\net45\MarkdownSharp.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\Microsoft.ApplicationBlocks.Data.dll + True + + + ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll + True + + + ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + True + + + ..\packages\Microsoft.Azure.Search.3.0.4\lib\net452\Microsoft.Azure.Search.dll + + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + True + + + ..\packages\Microsoft.Owin.Security.3.0.1\lib\net45\Microsoft.Owin.Security.dll + True + + + ..\packages\Microsoft.Owin.Security.Cookies.3.0.1\lib\net45\Microsoft.Owin.Security.Cookies.dll + True + + + ..\packages\Microsoft.Owin.Security.OAuth.3.0.1\lib\net45\Microsoft.Owin.Security.OAuth.dll + True + + + ..\packages\Microsoft.Rest.ClientRuntime.2.3.9\lib\net452\Microsoft.Rest.ClientRuntime.dll + + + ..\packages\Microsoft.Rest.ClientRuntime.Azure.3.3.9\lib\net452\Microsoft.Rest.ClientRuntime.Azure.dll + + + ..\packages\Microsoft.Spatial.7.2.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + + + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + True + + + ..\packages\Microsoft.Web.Xdt.2.1.1\lib\net40\Microsoft.Web.XmlTransform.dll + True + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + True + + + ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True + + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + ..\packages\semver.1.1.2\lib\net451\Semver.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\SQLCE4Umbraco.dll + True + + + + + + ..\packages\UmbracoCms.Core.7.5.3\lib\System.Data.SqlServerCe.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\System.Data.SqlServerCe.Entity.dll + True + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + True + + + ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + True + + + ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + True + + + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + True + + + + + + + + + ..\packages\UmbracoCms.Core.7.5.3\lib\TidyNet.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\Umbraco.Core.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.DataLayer.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.editorControls.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.MacroEngines.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\umbraco.providers.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\Umbraco.Web.UI.dll + True + + + ..\packages\UmbracoCms.Core.7.5.3\lib\UmbracoExamine.dll + True + + + ..\packages\UrlRewritingNet.2.0.7\lib\UrlRewritingNet.UrlRewriter.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + @@ -341,5 +340,5 @@ - --> + --> \ No newline at end of file