Elasticsearch.Net 使用 NEST 和嵌套对象进行查询以检索文档

Elasticsearch.Net query using NEST and nested objects to retrieve documents

我在应用程序中使用 Elasticsearch.Net 和 NEST,并且在基于嵌套对象 ID 进行搜索时无法访问 Elasticsearch 索引中的文档。数据结构是invoice -> lineItems -> rowItems。我想根据这些 rowItems Id 进行搜索。索引的(简化)映射是:

"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"
              }
            }
          }
        }
      }
    }
}

当我在 chrome 中对其中一个嵌套对象进行意义搜索时,我可以成功检索到它:

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

其中 returns 发票类型及其所有详细信息。

我一直在研究使用 NEST 执行此操作的代码,但到目前为止都失败了。我有一个 rowItemId 列表,我想获取与这些 ID 完全匹配的所有发票文档。这是我目前拥有的:

            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 是我要搜索的 rowItemId 列表。上面的代码是完全错误的,我不熟悉如何执行此操作的语法。任何帮助将不胜感激。

在您希望跨 对象 属性 的属性进行查询的情况下,需要嵌套类型。鉴于你的例子,

  1. 如果您只想在 lineItems 上查询 listItemslistItemID,那么使用 object type 就可以了。

  2. 如果要查询lineItems上的listItemIDitemName,您需要将 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")
        )
    )
);

获取字段名的lambda表达式就是这样; 获取字段名的表达式.

这会生成查询

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

由于 listItemID 是一个 not_analyzed 字符串字段,您可以在此处使用 term 查询,并且您可能不需要计算分数(match 在这种情况下是 truefalse),您可以将其包装在 bool 查询 filter 子句中,它可以利用过滤器缓存应该会稍微好一点。

要获取与一组 ID 匹配的文档,我们可以使用 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)
        )
    )
);

最后,shorthand 使用一元 + 运算符

将其包装在 bool 查询 filter 子句中
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)
        )
    )
);