-
Notifications
You must be signed in to change notification settings - Fork 635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DYN-6535 DynamoRevit Improve Search #14878
Changes from 3 commits
b10e7f0
906e11f
18a3e8f
ff1b100
584f794
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,6 +82,18 @@ public enum LuceneStorage | |
FILE_SYSTEM | ||
} | ||
|
||
public enum SearchType | ||
{ | ||
//Normal search using just one word matching a specific node name | ||
Normal, | ||
|
||
//Search by category using the "." character for example "list.re" | ||
ByCategory, | ||
|
||
//Search using an empty space as separator like "get parameters" or "set parameters" | ||
ByEmptySpace | ||
} | ||
|
||
// Used for creating the StandardAnalyzer | ||
internal Analyzer Analyzer; | ||
|
||
|
@@ -264,7 +276,13 @@ internal void SetDocumentFieldValue(Document doc, string field, string value, bo | |
/// <returns></returns> | ||
internal string CreateSearchQuery(string[] fields, string SearchTerm) | ||
{ | ||
//By Default the search will be normal | ||
SearchType searchType = SearchType.Normal; | ||
int fuzzyLogicMaxEdits = LuceneConfig.FuzzySearchMinEdits; | ||
|
||
//Max number of nodes allowed in the search when is a ByEmptySpace search | ||
const int MaxNodeNamesRepeated = 20; | ||
|
||
// Use a larger max edit value - more tolerant with typo when search term is longer than threshold | ||
if (SearchTerm.Length > LuceneConfig.FuzzySearchMaxEditsThreshold) | ||
{ | ||
|
@@ -273,13 +291,21 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) | |
|
||
var booleanQuery = new BooleanQuery(); | ||
string searchTerm = QueryParser.Escape(SearchTerm); | ||
var bCategoryBasedSearch = searchTerm.Contains('.') ? true : false; | ||
|
||
if (searchTerm.Contains('.')) | ||
searchType = SearchType.ByCategory; | ||
else if (searchTerm.Contains(' ')) | ||
searchType = SearchType.ByEmptySpace; | ||
else | ||
searchType = SearchType.Normal; | ||
|
||
var trimmedSearchTerm = searchType == SearchType.ByEmptySpace ? searchTerm.Replace(" ", "") : searchTerm; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the actual node name has spaces in it? Will those show up with this condition? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @reddyashish for the first question I think the Tokenizer that we are using is removing the empty spaces, just to confirm I've tested in DynamoSandbox with several nodes that use empty spaces and I'm getting the expected node always in first place (see image below) so there should not be any problem with nodes having empty space. For the second comment we are using SearchType.ByEmptySpace in more conditions in the code that's why I considered to add it in the SearchType enum. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for the confirmation @RobertGlobant20. Can't we just use that as a property to check for empty spaces then? Because the search algorithm is not altered, just the search term. Might not be a big thing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converted to be a property in the next commit: ff1b100 |
||
|
||
foreach (string f in fields) | ||
{ | ||
//Needs to be again due that now a query can contain different values per field (e.g. CategorySplitted:list, Name:tr) | ||
searchTerm = QueryParser.Escape(SearchTerm); | ||
if (bCategoryBasedSearch == true) | ||
if (searchType == SearchType.ByCategory) | ||
{ | ||
//This code section should be only executed if the search criteria is CategoryBased like "category.nodename" | ||
if (f != nameof(LuceneConfig.NodeFieldsEnum.NameSplitted) && | ||
|
@@ -297,26 +323,26 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) | |
} | ||
} | ||
|
||
FuzzyQuery fuzzyQuery; | ||
if (searchTerm.Length > LuceneConfig.FuzzySearchMinimalTermLength) | ||
{ | ||
fuzzyQuery = new FuzzyQuery(new Term(f, searchTerm), fuzzyLogicMaxEdits); | ||
booleanQuery.Add(fuzzyQuery, Occur.SHOULD); | ||
} | ||
|
||
//For normal search we don't consider the fields NameSplitted and CategorySplitted | ||
if ((f == nameof(LuceneConfig.NodeFieldsEnum.NameSplitted) || | ||
f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) && bCategoryBasedSearch == false) | ||
f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) && searchType != SearchType.ByCategory) | ||
continue; | ||
|
||
//This case is for when the user type something like "list.", I mean, not specifying the node name or part of it | ||
if (string.IsNullOrEmpty(searchTerm)) | ||
continue; | ||
|
||
var fieldQuery = CalculateFieldWeight(f, searchTerm); | ||
var wildcardQuery = CalculateFieldWeight(f, searchTerm, true); | ||
FuzzyQuery fuzzyQuery; | ||
if (searchTerm.Length > LuceneConfig.FuzzySearchMinimalTermLength) | ||
{ | ||
fuzzyQuery = new FuzzyQuery(new Term(f, searchType == SearchType.ByEmptySpace ? trimmedSearchTerm : searchTerm), fuzzyLogicMaxEdits); | ||
booleanQuery.Add(fuzzyQuery, Occur.SHOULD); | ||
} | ||
|
||
if (bCategoryBasedSearch && f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) | ||
var fieldQuery = CalculateFieldWeight(f, searchType == SearchType.ByEmptySpace ? trimmedSearchTerm : searchTerm); | ||
var wildcardQuery = CalculateFieldWeight(f, searchType == SearchType.ByEmptySpace ? trimmedSearchTerm : searchTerm, true); | ||
|
||
if (searchType == SearchType.ByCategory && f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) | ||
{ | ||
booleanQuery.Add(fieldQuery, Occur.MUST); | ||
booleanQuery.Add(wildcardQuery, Occur.MUST); | ||
|
@@ -331,6 +357,10 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) | |
{ | ||
foreach (string s in searchTerm.Split(' ', '.')) | ||
{ | ||
//If is a ByEmptySpace search and the splitted words match with more than MaxNodeNamesRepeated nodes then the word is skipped | ||
int nodesFrequency = dynamoModel.SearchModel.Entries.Where(entry => entry.Name.ToLower().Contains(s) && !string.IsNullOrEmpty(s)).Count(); | ||
if (nodesFrequency > MaxNodeNamesRepeated) continue; | ||
|
||
if (string.IsNullOrEmpty(s)) continue; | ||
|
||
if (s.Length > LuceneConfig.FuzzySearchMinimalTermLength) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments for public fields please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added extra comments: 584f794