2017-01-30 19 views
0

Я использую Elasticsearch.Net и NEST в приложении и имею проблемы с доступом к документам в индексе Elasticsearh при поиске на основе идентификаторов вложенных объектов. Структура данных - это счет-фактура -> lineItems -> rowItems. Я хочу искать на основе этих идентификаторов rowItems. (Упрощенный) отображение индекса:Запрос Elasticsearch.Net с использованием NEST и вложенных объектов для извлечения документов

"invoice": { 
    "properties": { 
     "lineItems": { 
     "properties": { 
      "accountId": { 
      "index": "not_analyzed", 
      "type": "string" 
      }, 
      "listItems": { 
      "properties": { 
       "itemName": { 
       "analyzer": "str_index_analyzer", 
       "term_vector": "with_positions_offsets", 
       "type": "string", 
       "fields": { 
        "raw": { 
        "analyzer": "str_search_analyzer", 
        "type": "string" 
        } 
       } 
       }, 
       "listItemID": { 
       "index": "not_analyzed", 
       "type": "string" 
       } 
      } 
      } 
     } 
     } 
    } 
} 

И когда я делаю поиск смысла в хроме одной из вложенных объектов, я могу успешно получить его:

POST /_search 
{ 
    "query": { 
    "bool": { 
     "should": [ 
     {"match": { 
      "lineItems.rowItems.rowItemID" : "23f2157f-eb21-400d-b3a1-a61cf1451262"    
     }} 
     ] 
    } 
    } 
} 

который возвращает тип документа Счет со всеми его подробностями.

Я играл с кодом, чтобы сделать это, используя NEST, но до сих пор не удалось. У меня есть список rowItemIds, и я хочу получить все документы-фактуры, которые имеют точное совпадение с этими идентификаторами. Это то, что я в настоящее время:

  var result = Execute(client => client.Search<Invoice>(s => s 
    .Aggregations(a => a 
     .Nested("my_nested_agg", n => n 
      .Path("lineItems") 
      .Aggregations(aa => aa 
       .Filter("my_avg_agg", avg => avg 
        .Field(p => searchIds.Contains(p.LineItems.First().RowItems.First().TrackingItemID)) 
       ) 
      ) 
     ) 
    ) 
)); 

Где searchIds список rowItemIds Я ищу. Вышеприведенный код совершенно неверен, и я не знаком с синтаксисом о том, как это сделать. Любая помощь будет принята с благодарностью.

+0

Я заметил здесь: http://stackoverflow.com/questions/29346935/elasticsearch-nested-object-under-path-is-not-of-nested-type , что вложенное ключевое слово необходимо для выполнения вложенных поисков, таких как: «type»: «inested» Возможно ли найти эти идентификаторы без этого (чего у меня нет). Кроме того, весь реиндекс не является опцией в настоящий момент задержек в системе. – CorribView

ответ

1

Вложенные типы необходимы в сценариях, где вы хотите запросить свойства объекта . Учитывая ваш пример,

  1. Если вы хотите только запросить listItemID из listItems на lineItems затем имея object type для этого будет работать нормально.

  2. Если вы хотите чтобы запросить listItemIDиitemName из listItems на lineItems, вам нужно будет карту listItems как nested type.

Причина этого заключается в том, что без использования nested типа, ассоциация между свойствами конкретного listItem не сохраняются при индексировании. С типом nested ассоциация сохраняется (nested типы внутренне хранятся как документы).

Поисковый запрос, который у вас есть, очень похож на NEST; match запрос не должен содержаться в bool запроса should статьи в в этом случае

var client = new ElasticClient(); 

var searchResponse = client.Search<Invoice>(s => s 
    .AllIndices() 
    .AllTypes() 
    .Query(q => q 
     .Match(m => m 
      .Field(f => f.LineItems.First().ListItems.First().ListItemID) 
      .Query("23f2157f-eb21-400d-b3a1-a61cf1451262") 
     ) 
    ) 
); 

лямбда-выражения, чтобы получить имя поля только что; выражение, чтобы получить имя поля.

Это генерирует запрос

POST http://localhost:9200/_search 
{ 
    "query": { 
    "match": { 
     "lineItems.listItems.listItemID": { 
     "query": "23f2157f-eb21-400d-b3a1-a61cf1451262" 
     } 
    } 
    } 
} 

так listItemID это поле not_analyzed строки, вы можете использовать term запрос здесь вместо этого и, так как вы, вероятно, не нужен счета вычисленного (а матча в этом случае либо true, либо false), вы можете обернуть это в bool запрос filter, который может использовать кеширование фильтра и должен работать немного лучше.

Чтобы получить эти документы, которые соответствуют набор идентификаторов, мы можем использовать terms запрос,

var ids = new[] { 
    "23f2157f-eb21-400d-b3a1-a61cf1451262", 
    "23f2157f-eb21-400d-b3a1-a61cf1451263", 
    "23f2157f-eb21-400d-b3a1-a61cf1451264" 
}; 

var searchResponse = client.Search<Invoice>(s => s 
    .AllIndices() 
    .AllTypes() 
    .Query(q => q 
     .Terms(m => m 
      .Field(f => f.LineItems.First().ListItems.First().ListItemID) 
      .Terms(ids) 
     ) 
    ) 
); 

И, наконец, стенографии для упаковки этого в запросе filter статье в bool, используя унарный + оператор

var searchResponse = client.Search<Invoice>(s => s 
    .AllIndices() 
    .AllTypes() 
    .Query(q => +q 
     .Terms(m => m 
      .Field(f => f.LineItems.First().ListItems.First().ListItemID) 
      .Terms(ids) 
     ) 
    ) 
); 
+0

Удивительный, спасибо Руси за то, что я понял, что я запутался в отношении вложенных/объектов. Я внедрил ваш код и могу успешно получить твердокодированный идентификатор. Одна заключительная часть: если у меня есть массив идентификаторов, как я могу изменить выше, так что он ищет все идентификаторы в массиве, а не только один. – CorribView

+0

Я отредактирую свой ответ, чтобы включить –

+0

Удивительный, он работает. Цените помощь на этом, тщательном и описательном ответе! – CorribView