bigerock
bigerock

Reputation: 713

load specific fields in Elasticsearch Nest query

the documentation seems to indicate i can return a subset of fields instead of the entire document. here's my code:

var result = client.Search<MyObject>(s => s
                .Fields(f => f.Title)
                .Query(q => q
                    .QueryString(qs => qs
                        .OnField("title")
                        .Query("the"))));

i'm searching on the word 'the' on the 'title' field and wanting to just return 'title'. my result.Documents object contains 10 objects that are each null.

i do see the values i want but it's deep in the search response: result.Hits[0].Fields.FieldValues[0]...

is there a better way to get at the list of 'title' fields returned?

my mapping for the data (truncated) is this ...

{
   "myidex": {
      "mappings": {
         "myobject": {
            "properties": {
               "title": {
                  "type": "string"
               },
               "artists": {
                  "properties": {
                     "id": {
                        "type": "string",
                        "index": "not_analyzed",
                        "analyzer": "fullTerm"
                     },
                     "name": {
                        "type": "string",
                        "index": "not_analyzed",
                        "analyzer": "fullTerm"
                     }
                  }
               }                             
            }
         }
      }
   }
}

and my class objects are like this:

[Table("MyTable")]
[Serializable]
[ElasticType(Name="myobject")]
public class MyObject
{
    [ElasticProperty]
    public string Title { get; set; }

    [JsonIgnore]
    public string Artistslist { get; set; }
    [ElasticProperty(Analyzer = "caseInsensitive")]
    public List<Person> Artists { get; set; }        
}

[Serializable]
public class Person
{
    [ElasticProperty(Analyzer = "fullTerm", Index = FieldIndexOption.not_analyzed)]
    public string Name { get; set; }
    [ElasticProperty(Analyzer = "fullTerm", Index = FieldIndexOption.not_analyzed)]
    public string Id { get; set; }
}

Artistslist comes from my data source (sql) then i parse it out into a new List object before indexing the data.

Upvotes: 3

Views: 6417

Answers (2)

ozzimpact
ozzimpact

Reputation: 111

I found the solution in Nest's Github repo. They have created an issue about this problem. You should use FielddataFields instead of Fields.

https://github.com/elastic/elasticsearch-net/issues/1551

var result = client.Search<MyObject>(s => s
                .FielddataFields(f => f.Title)
                .Query(q => q
                    .QueryString(qs => qs
                        .OnField("title")
                        .Query("the"))));

and in response you see FieldSelections. You get the fields that you wanted.

Upvotes: 3

Paige Cook
Paige Cook

Reputation: 22555

I think this deeply nested value is do to a change in Elasticsearch 1.0 and how partial fields are now returned as arrays (See 1.0 Breaking Changes - Return Values for details.). This is addressed in the NEST 1.0 Breaking Changes documentation; in the Fields() vs SourceIncludes() section. It shows an example of using a FieldValue helper method to gain access to these values. Based on that, try the following:

For all items:

 foreach (var hit in result.Hits)
 {
     var title = hit.Fields.FieldValue<MyObject, string>(f => f.Title);
 }

For a specific item:

 var title = result.Hits.ElementAt(0)
                  .Fields.FieldValue<MyObject, string>(f => f.Title);

I know it is still a bit verbose but it should work for you and will handle the new array return formatting of Elasticsearch 1.0.

Upvotes: 4

Related Questions