有没有一种方法可以在没有额外循环的情况下反序列化搜索结果中的脚本字段值?

Is there a way to deserialize script field values on a search result without an extra loop?

我需要使用 Script Fields in my .net code, in order to run some query logic on Elasticsearch. This doc 说:

Script fields can be accessed on the response using .Fields, similarly to stored fields.

为了检索脚本字段结果,我似乎需要遍历结果(按照建议 here or here)。我想避免该循环,并以某种方式在我对 NEST 的 client.search() 的调用中获取数据,它已经填充了结果列表。这可能吗?

这是我的电话:

    public async Task<List<SomeObj>> GetSomeDocsFromEs()
    {
        var result = await client.SearchAsync<SomeObj>(s => s
            .Index(...)
            .Query(...)
            .Size(...)
            .From(...)
            .Sort(...)
            .ScriptFields(sf => sf
                     .ScriptField("StoredField1", sc => sc
                        .Source(some Painless script)
                     )
                     .ScriptField("StoredField2", sc => sc
                        .Source(some Painless script)
                     )
                     .ScriptField("StoredField3", sc => sc
                        .Source(some Painless script)
                      )
                )
            .StoredFields(sf => sf
                    .Fields(
                            f => f.StoredField1,
                            f => f.StoredField2,
                            f => f.StoredField3
                    )
                )
            .Source(so => so
                .Includes(i => i
                    .Fields(f => f.SkuEntry.Field1,
                            f => f.SkuEntry.Field2,
                            f => f.SkuEntry.Field3
                    )
                )
            )
        );

        return result.Documents.ToList();
    }

I want to avoid that loop, and somehow get the data within my call to NEST's client.search(), which already populates a list of results. Is that possible?

对于命中数组中的每个命中,都会返回脚本字段,因此无法避免循环命中。

示例中的

result.Documents 映射到每个文档的 _source 字段,这是发送到 Elasticsearch 并建立索引的原始 JSON 对象。 result.Hits.Select(h => h.Source).ToList().

很方便 shorthand

脚本字段不是 _source 文档的一部分,它们在每次点击的单独字段中返回。 result.Fieldsresult.Hits.Select(h => h.Fields).ToList() 的方便 shorthand。

例如,给定以下查询

var searchResponse = client.Search<Project>(s => s
    .ScriptFields(sf => sf
        .ScriptField("test1", sc => sc
            .Source("doc['numberOfCommits'].value * 2")
        )
        .ScriptField("test2", sc => sc
            .Source("doc['numberOfCommits'].value * params.factor")
            .Params(p => p
                .Add("factor", 2.0)
            )
        )
    )
);

发送以下请求

{
  "script_fields": {
    "test1": {
      "script": {
        "source": "doc['numberOfCommits'].value * 2"
      }
    },
    "test2": {
      "script": {
        "source": "doc['numberOfCommits'].value * params.factor",
        "params": {
          "factor": 2.0
        }
      }
    }
  }
}

JSON 响应是

{
  "took" : 26,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1100,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "project",
        "_type" : "_doc",
        "_id" : "Konopelski Inc2032",
        "_score" : 1.0,
        "_routing" : "Konopelski Inc2032",
        "fields" : {
          "test2" : [
            308.0
          ],
          "test1" : [
            308
          ]
        }
      },
      {
        "_index" : "project",
        "_type" : "_doc",
        "_id" : "Feest Group2047",
        "_score" : 1.0,
        "_routing" : "Feest Group2047",
        "fields" : {
          "test2" : [
            1986.0
          ],
          "test1" : [
            1986
          ]
        }
      }
    ]
  }
}

迭代响应中每个命中的脚本字段

foreach (var fields in response.Fields)
{
    // do something with test1 and test2 values
    var test1 = fields.Value<int>("test1");
    var test2 = fields.Value<double>("test2");
}