Search code examples
c#asp.netelasticsearchkibananest

How to select only matching fields of child object in ElasticSearch?


I am facing a problem with searching with Elasticsearch. I am using ES 7.3 for my implementation.

Below is my class structure:

    [ElasticsearchType]
    public class InquiryInformation
    {
        [Text(Name = "inquiryNumber")]
        public string InquiryNumber { get; set; }

        [Text(Name = "inquiryStatus")]
        public string InquiryStatus { get; set; }

        [Text(Name = "submitedBy")]
        public string SubmittedBy { get; set; }

        [Nested]
        [PropertyName("files")]
        public List<FileInformation> Files { get; set; }

    }

    [ElasticsearchType]
    public class FileInformation
    {
        [Text(Name = "fileName")]
        public string FileName { get; set; }

        [Text(Name = "fileContent")]
        public string FileContent { get; set; }
    }

And used this code to create a mapping:

elasticClient.Map<InquiryInformation>(m => m.AutoMap());

This has created below index mapping with ES:

{
  "city" : {
    "mappings" : {
      "properties" : {
        "files" : {
          "type" : "nested",
          "properties" : {
            "fileContent" : {
              "type" : "text"
            },
            "fileName" : {
              "type" : "text"
            }
          }
        },
        "inquiryNumber" : {
          "type" : "text"
        },
        "inquiryStatus" : {
          "type" : "text"
        },
        "submitedBy" : {
          "type" : "text"
        }
      }
    }
  }
}

Now, I have to write a query which will search for Users as well as user's files.

Lets say If I search for user with inquiryNumber XYZ1212 then it will return me all the matching records. Now the problem is - I need to return only the matching files. Like if FileName of FileContent contains the matching record information then only matched files should be returned along with document.

I have tried so many ways with NEST. But Failed to get the only matched files. Its always returning me all the files for a specific user.

Any luck for this to achieve my needs ?

UPDATE 1 Adding Sample Query of C# (NEST)

var searchResult = elasticClient.Search<InquiryInformation>(s => s
                    .Query(q => q
                        .MultiMatch(m => m
                            .Fields(f => f
                                .Field("files.fileContent")
                                .Field("files.fileName")
                            )
                            .Query("Hello Stackoverflow")
                        )
                    )
                );

UPDATE 2 : Adding another query:

POST city/_search
{
  "_source": {
    "includes": [ "*" ],
    "excludes": [ "files" ]
  },
  "query": {
    "nested": {
      "path": "files",
      "inner_hits": {
        "_source": [
          "inquiryNumber", "submitedBy"
        ]
      },
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "files.fileContent": "Samsung"
              }
            }
          ]
        }
      }
    }
  }
}

Solution

  • Since the files field is a nested field, you need to leverage a nested query as well. Something like this:

     var searchResult = elasticClient.Search<InquiryInformation>(s => s
                    .Source(false)
                    .Query(q => q
                       .Nested(c => c
                          .InnerHits()
                          .Path(p => p.Files)
                          .Query(nq => nq
                            .MultiMatch(m => m
                              .Fields(f => f
                                .Field("files.fileContent")
                                .Field("files.fileName")
                              )
                              .Query("Hello Stackoverflow")
                            )
                          )
                       )
                    )
                );