2015-01-21 7 views
0

Я пытаюсь настроить lucene.net 3, чтобы иметь возможность искать по двум полям для фразы, и я застреваю. Вот что я хотел бы для запроса, чтобы вернуться:MultiFieldQueryParser и подстановочные знаки

Я хочу, чтобы запрос, чтобы вернуть точную фразу соответствует как:

фраза: «CHING WAN HUNG SOOTHING ТРАВЯНОЙ БАЛЬЗАМ»

результат: «CHING WAN HUNG SOOTHING ТРАВЯНОЙ БАЛЬЗАМ»

Как спички Wildcard:

фраза: "CHING WAN HUNG СОО" ИЛИ "CHING WAN HUN"

результат: «CHING WAN HUNG SOOTHING HERBAL BALM» и другие, которые могут соответствовать этому или любому другому неполному варианту фразы.

Мое первоначальное решение состояло в том, чтобы создать логический запрос с фразерой и запросом, который анализирует и подталкивает каждое слово.

Но это возвращает матч, а также слишком много результатов, которые не близки к применимости. (Он вернет «HERBAL TEA», так как «HERBAL» является одним из разобранных терминов ...) Из-за анализируемого запроса OR.

Это связано с оригинальным сообщением, которое у меня было: How to set up a query to return phrases and parts of phrases in lucene.net? Было интересно, могу ли я сделать это в стандартном Lucene.net, не обращаясь к упомянутому порту Java.

Может ли кто-нибудь дать мне какие-либо рекомендации по этому поводу? Спасибо!

public override List<TT> ExecuteSearch(string searchQuery, string searchField = "") 
{ 
    if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<TT>(); 

    using (var searcher = new IndexSearcher(Directory, false)) 
    { 
     var hits_limit = 1000; 
     var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30, new HashSet<string>()); 
     var fields = new[] {"CompositeName", "SubstanceName"}; 

     var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, analyzer); 
     parser.AllowLeadingWildcard = true; 
     parser.PhraseSlop = 0; 
     var query = ParseWholeQueryWc(searchQuery, fields, parser); 
     searcher.SetDefaultFieldSortScoring(true, true); 
     var hits = searcher.Search(query, null, hits_limit, Sort.RELEVANCE).ScoreDocs; 
     var results = MapLuceneToDataList(hits, searcher); 
     analyzer.Close(); 
     searcher.Dispose(); 
     return results; 
    } 
} 

public Query ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser) 
{ 
    Query query = new PhraseQuery(); 
    Query query2 = new PhraseQuery(); 
    Query mq = new BooleanQuery(); 

    try 
    { 
     var bld = ParseTermWithWildcards(searchQuery); 

     // phrase 
     query = parser.Parse("\"" + searchQuery.Trim() + "\""); 

     // or 
     query2 = parser.Parse(searchQuery + "*"); 

     // main 
     ((BooleanQuery)mq).Add(query, Occur.SHOULD); 
     ((BooleanQuery)mq).Add(query2, Occur.SHOULD); 
    } 
    catch (ParseException ex) 
    { 
     throw; 
    } 
    return mq; 
} 

UPDATE

public BooleanQuery ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser) 
    { 
     BooleanQuery mq = new BooleanQuery(); 

     try 
     { 
      string[] qrArr = searchQuery.Split(null); 
      SpanQuery[] compNmQ = new SpanQuery[qrArr.Length]; 
      SpanQuery[] subsNmQ = new SpanQuery[qrArr.Length]; 

      for (var i = 0; i < qrArr.Length; i++) 
      { 
       //CompositeName", "SubstanceName 
       if (i == qrArr.Length - 1) 
       { 
        compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i] + "*")); 
        subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i] + "*")); 
       } 
       else 
       { 
        compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i])); 
        subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i])); 
       } 
      } 

      SpanQuery compNameQ = new SpanNearQuery(compNmQ, 0, true); 
      SpanQuery subsNameQ = new SpanNearQuery(subsNmQ, 0, true); 

      // main 
      ((BooleanQuery) mq).Add(compNameQ, Occur.SHOULD); 
      ((BooleanQuery)mq).Add(subsNameQ, Occur.SHOULD); 
     } 
     catch (ParseException ex) 
     { 
      throw new ArgumentException("BaseLuceneStrategy:ParseWholeQueryWc():" + ex.Message); 
     } 
     return mq; 
    } 

Это теперь будет возвращать ноль хитов.

ответ

1

Если вы хотите, чтобы все условия были необходимы независимо от порядка или близости, в котором они отображаются, это простое исправление. Просто добавьте:

parser.setDefaultOperator(QueryParser.Operator.AND); 

Если все ваши запросы будут начинаться в начале поля вы хотите, чтобы соответствовать, то вы можете изменить поле к быть непроанализированным. Если он не анализируется, тогда будет выполняться простой запрос подстановки. Это не будет хорошим решением, однако, если вы хотите, чтобы иметь возможность запросить что-то вроде: "HUNG SOOTHING HERBAL"


В качестве альтернативы, SpanQueries на помощь. Это, конечно, лучше в Java, так как в v3.1 мы получили SpanMultiTermQueryWrapper работать, но в 3.0.3 (и, таким образом, порт .Net, а), вы можете сделать с SpanRegexQuery:

SpanQuery[] subqueries = new SpanQuery[4]; 
subqueries[0] = new SpanTermQuery(new Term("field", "CHING")); 
subqueries[1] = new SpanTermQuery(new Term("field", "WAN")); 
subqueries[2] = new SpanTermQuery(new Term("field", "HUNG")); 
subqueries[3] = new SpanRegexQuery(new Term("field", "SOO.*")); 
SpanQuery finalQuery = new SpanNearQuery(subqueries, 0, true) 

Сделайте то же самое для любых других полей и объедините их в BooleanQuery.

+0

Спасибо femtoRgon, я создал это и теперь возвращает нулевые записи. Я добавил свой модифицированный код по вашему предложению выше в своем оригинальном посте. – melmack

+0

Возможно, из-за анализа. Имейте в виду, что анализаторы здесь не будут применяться. Похоже, вы используете StandardAnalyzer, который уменьшает все, поэтому вам нужно будет очертить условия поиска. – femtoRgon

+0

Я топнул струну, и она работает хорошо. Только дело в том, что он получает нулевые удары, когда я пытаюсь найти «CHING WAN HUNG SOOTHING HERBAL BA» или «CHING WAN HUNG SOOTHING HERBAL BAL». Любая идея почему? Еще раз спасибо за ответ. – melmack

Смежные вопросы