2015-04-19 3 views
4

Короткая версия:Elasticsearch Nest подстановочные запрос с пробелами

Я хотел бы написать упругую поисковый запрос, используя гнездо, чтобы получить полные индексированные элементы (ContentIndexables в моем случае, как мой пользовательский тип), которые были проиндексированы. Запрос подлежит термину query [some string] + * (т. Е. String.StartsWith(), где [некоторая строка] может содержать или не содержать пробелы.

Это отличается от CompletionSuggester, так как мне нужно получить полный объект, а не строка предложения

То, что я пытался до сих пор:.

Когда я запрашиваю для текста без пробелов, желаемый результат будет возвращен, используя этот код Если мой поисковый термин, однако содержит пробелы. , он не возвращает ожидаемых результатов.

Вот как я искать поля:

var searchResults = _client.Search<ContentIndexable>(
      body => 
      body 
       .Index(indexName) 
       .Query(
        query => 
        query.QueryString(
         qs => qs. 
            OnFields(f => f.Title, f => f.TextContent) 
            .Query(searchTerm + "*")))); 

И это тест блок, который показывает, как воспроизвести проблему:

indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable 
     { 
      ContentId = Guid.NewGuid(), 
      TextContent = "Some description", 
      Title = "title" 
     }); 

     indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable 
     { 
      ContentId = Guid.NewGuid(), 
      TextContent = "Some description", 
      Title = "title that is long" 
     }); 

     indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable 
     { 
      ContentId = Guid.NewGuid(), 
      TextContent = "Some description", 
      Title = "title that likes" 
     }); 

     indexService.IndexUserItemsSync(testGuid, IndexType.submission, new ContentIndexable 
     { 
      ContentId = Guid.NewGuid(), 
      TextContent = "Some description", 
      Title = "titlethat" 
     }); 

     var searchResult = indexService.SearchUserItems(testGuid, IndexType.submission, 10, "title"); 
     Assert.IsNotNull(searchResult); 
// this one works 
     Assert.AreEqual(4, searchResult.Count()); 

     var searchResult2 = indexService.SearchUserItems(testGuid, IndexType.submission, 10, "title that"); 
     Assert.IsNotNull(searchResult2); 
// this one does not!!! searchREsult2.Count() evaluates to 0 
     Assert.AreEqual(2, searchResult2.Count()); 

Как вы можете видеть, то я вхожу «титул, который», то поиск возвращается пустой, а не две строки, которые я ожидал бы вернуться.

Update: Некоторые больше информации: создать индекс по моему типу ContentIndexable:

public class ContentIndexable : IIndexable 
{ 
    public Guid ContentId { get; set; } 
    public string Title { get; set; } 
    public string TextContent { get; set; } 
} 

С помощью этого кода:

_client.CreateIndex(
    indexName, 
    descriptor => 
    descriptor.AddMapping<ContentIndexable>(
     m => m.Properties(
      p => p.Completion(s => s 
             .Name(n => n.Title) 
             .IndexAnalyzer("standard") 
             .SearchAnalyzer("standard") 
             .MaxInputLength(30) 
             .Payloads() 
             .PreserveSeparators() 
             .PreservePositionIncrements()) 
        .Completion(s => s.Name(n => n.TextContent) 
              .IndexAnalyzer("standard") 
              .SearchAnalyzer("standard") 
              .MaxInputLength(50) 
              .Payloads() 
              .PreserveSeparators() 
              .PreservePositionIncrements()) 
       ))); 

Я даже пытался избежать пробелов и когда Я индексирую или когда я запрашиваю string.Replace(" ", @"\ "), но это не помогло.

Изменение типа поиска на джокера не помогло:

var searchResults = _client.Search<ContentIndexable>(
      body => 
      body 
       .Index(indexName) 
       .Query(
        query => query.Wildcard(qd => qd.OnField(f => f.Title).Value(searchTerm + "*")))); 

Кто-нибудь знает, что я делаю неправильно?

Обратите внимание: моя версия CompletionSuggester работает с пробелами, но, к сожалению, только возвращает строки. Мне нужно получить полный товар, чтобы получить ContentId. МОЯ реализация CompletionSuggester:

public IEnumerable<string> GetAutoCompleteSuggestions(Guid userId, IndexType indexType, int size, string searchTerm) 
    { 
     string indexName = getIndexName(indexType, userId); 

     var result = _client.Search<ContentIndexable>(
      body => body.Index(indexName) 
         .SuggestCompletion("content-suggest" + Guid.NewGuid(), 
              descriptor => descriptor 
                  .OnField(t => t.Title) 
                  .Text(searchTerm) 
                  .Size(size))); 

     if (result.Suggest == null) 
     { 
      return new List<string>(); 
     } 

     return (from suggest in result.Suggest 
       from value in suggest.Value 
       from options in value.Options 
       select options.Text).Take(size); 
    } 

Я знаю, что может принять предложения, получить полную отдачу (что приведет к двум пунктам я ожидал), а затем сделать полный термин матч, используя свой первый метод, но что требует 2 отдельных вызова в ElasticSearch (один для полного предложения и второй для запроса термина), но в идеале я хотел бы сделать это без кругового путешествия, если это возможно.

Большое спасибо заранее,

+0

Вы пытаетесь внедрить [завершение семинара] (http://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html), или, скорее, ваше сопоставление - это что-то вроде «возможно это будет работать »? – Rob

+0

Привет @Rob. Я уже сделал завершающего экзаменатора, но это возвращает мне список строк. Этот список является правильным и содержит элементы с пробелами правильно. То, что я хотел бы сделать, - это сделать то же самое с запросом, который дает мне тот же результат (с пробелами), но вместо строк в качестве предложений мне нужно получить весь проиндексированный объект (ContentIndexable в моем случае). Я полный новичок в ElasticSearch, как вы, возможно, догадались, поэтому любое предложение будет оценено по достоинству. – kha

ответ

1

Это пример того, как вы можете иметь дело с вашей проблемой для Title области.

Изменить отображение на что-то подобное (или использовать MultiField, но я не мог найти опцию для отображения поля в виде строки и завершения в то же время):

client.CreateIndex(indexName, i => i 
    .AddMapping<ContentIndexable>(m => m 
     .Properties(
      ps => ps 
       .Completion(c => c.Name("title.completion") 
        .IndexAnalyzer("standard") 
        .SearchAnalyzer("standard") 
        .MaxInputLength(30) 
        .Payloads() 
        .PreserveSeparators() 
        .PreservePositionIncrements()) 
       .String(s => s.Name(x => x.Title).CopyTo("title.completion"))))); 

изменить вашу SuggestCompletion к

var result = client.Search<ContentIndexable>(body => body 
    .Index(indexName) 
    .SuggestCompletion("content-suggest" + Guid.NewGuid(), 
     descriptor => descriptor 
      .OnField(t => t.Title.Suffix("completion")) 
      .Text("title") 
      .Size(10))); 

и QueryString к

var searchResponse = client.Search<ContentIndexable>(body => body 
    .Index(indexName) 
    .Query(query => query 
     .QueryString(
      qs => qs 
       .OnFields(f => f.Title.Suffix("completion")) 
       .Query("title tha" + "*") 
       .MinimumShouldMatchPercentage(100)))); 

Проблема с этим решением заключается в том, что мы дважды сохраняем данные для поля Title. Вот почему я упомянул ранее, что было бы здорово использовать MultiField, но я не смог сделать это с помощью NEST.

Надеюсь, это поможет.

+0

Большое спасибо. Это сработало с тем исключением, что если в строке запроса содержались неавиационные числовые символы, он ничего не вернул бы. Перед тем, как выполнить запрос, я удаляю эти символы сейчас, и он отлично работает. – kha

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