简体   繁体   中英

Elasticsearch Nest 2.x index nested object

I'm new in Elasticsearch and Nest and blocked in a problem. What I want to do is create a index and index a doc with nested fields.

    [ElasticsearchType]
public class TestType
{
    [Nest.String(Store = true, Index = FieldIndexOption.Analyzed )]
    public string  Text { get; set; }

    [Nested(IncludeInAll = true)]
    public List<NestedTestType> Nests { get; set; } = new List<NestedTestType>();

    public string Id { get; set; }      
}

[ElasticsearchType]
public class NestedTestType
{
    [Nest.String(Store = true, Index = FieldIndexOption.Analyzed)]
    public string Value { get; set; }

    [Nest.String(Store = false)]
    public string NotStoredValue { get; set; }
}

and in the function it is

            var connectionPool = new Elasticsearch.Net.SniffingConnectionPool(poolUris);
        var settings = new ConnectionSettings(connectionPool);
        client = new ElasticClient(settings);

        string testIndexName = "test";
        var createIndeReponse = client.CreateIndex(testIndexName);
        var mappingResponse = client.Map<TestType>(m => m.Index(testIndexName).AutoMap());
       mappingResponse = client.Map<NestedTestType>(m => m.Index(testIndexName).AutoMap());

        TestType testData = new TestType() { Text = "Hello world" };
        testData.Nests.Add( new NestedTestType() { Value = "In the list", NotStoredValue = "Not stored"} );

        IndexRequest<TestType> indexRequest = new IndexRequest<TestType>(testIndexName, "test_type");
        indexRequest.Document = testData;
        IIndexResponse iir = client.Index(indexRequest);

However, the iir in the last line contains an error "object mapping [nests] can't be changed from nested to non-nested"

My questions are :

What is the correct way to do the indexing? Where can I find documentation which will help me further?

A few observations:

  • The type names for both TestType and NestedTestType will be inferred from the CLR type name. By default, these will be the camel cased version of the type name ie testType and nestedTestType , respectively.

  • Since NestedTestType is a nested type on TestType , you don't need to add a mapping separately for it in the index; the mapping of NestedTestType is part of the mapping of TestType

  • You don't specify a value for the Id of TestType ; NEST will infer the id of the document from the Id property which will be null; Elasticsearch will be fine with this and generate a unique id for the document, storing it in the _id field, but this unique id will not be set against the Id property in _source meaning there would be no easy way of retrieving this document by id using NEST conventions. I'd recommend setting a value for Id and also mapping the field as not_analyzed

The reason for the error is that when indexing TestType , you specify the type name to be test_type as opposed to explicitly specifying testType or just letting NEST infer it for you.

When Elasticsearch sees the json document coming in, it doesn't associate it with the mapping for TestType that was created earlier since the type names don't match ( testType vs. test_type ) so attempts to map nests as an object. But , the index does contain a nested mapping already for objects under the path nests , which is giving rise to the error.

To solve, we can do

var connectionPool = new Elasticsearch.Net.SniffingConnectionPool(poolUris);
string testIndexName = "test";

var settings = new ConnectionSettings(connectionPool)
    // specify test to be the default index, meaning if no index name
    // is explicitly passed to a request or inferred from the type,
    // this will be the default
    .DefaultIndex(testIndexName);

var client = new ElasticClient(settings);

// create the index and add the mapping at the same time
var createIndeReponse = client.CreateIndex(testIndexName, c => c
    .Mappings(m => m
        .Map<TestType>(mm => mm.AutoMap())
    )
);

TestType testData = new TestType { Text = "Hello world", Id = "1" };
testData.Nests.Add(new NestedTestType { Value = "In the list", NotStoredValue = "Not stored" });

IIndexResponse iir = client.Index(testData);

If you want to specify that TestType should be mapped as the type name test_type , you can use MapDefaultTypeNames on connection settings

var settings = new ConnectionSettings(connectionPool)
    .DefaultIndex(testIndexName)
    .MapDefaultTypeNames(d => d
        .Add(typeof(TestType), "test_type")
    );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM