Mant101 Mant101 - 3 months ago 58
C# Question

Elastic search with GUID ID without attributes

We are looking to switch from a relational database to elastic search and I am trying to get some basic code up and running with Nest. We have existing objects which use guids for ids that I would like to save into an elastic search index.

I don't want to add any specific attributes as the class is used in different applications and I don't want to add unnecessary dependencies to Nest.

Right now my code looks like this:

var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node)
settings.DefaultIndex = "test";
var client = new ElasticClient(settings);

var testItem = new TestType { Id = Guid.NewGuid(), Name = "Test", Value = "10" };

var response = client.Index(testItem);


With TestType as:

public class TestType
{
public Guid Id { get; set; }
public string Name { get; set; }
public decimal Value { get; set; }
}


However I get an error like:


ServerError: 400Type: mapper_parsing_exception Reason: "failed to
parse [id]" CausedBy: "Type: number_format_exception Reason: "For
input string: "c9c0ed42-86cd-4a94-bc86-a6112f4c9188""


I think I need to specify a mapping that tells the server the Id is a string, but I can't find any examples or documentation on how I do this without using the attributes.

Answer

Assuming you're using Elasticsearch 2.x and NEST 2.x (e.g. latest of both at time of writing is Elasticsearch 2.3.5 and NEST 2.4.3), then NEST will automatically infer the id of a POCO by default from the Id property. In the case of a GUID id, this will be saved as a string in Elasticsearch.

Here's an example to get you going

void Main()
{
    var node = new Uri("http://localhost:9200");
    var settings = new ConnectionSettings(node)
        // default index to use if one is not specified on the request
        // or is not set up to be inferred from the POCO type
        .DefaultIndex("tests");

    var client = new ElasticClient(settings);

    // create the index, and explicitly provide a mapping for TestType
    client.CreateIndex("tests", c => c
        .Mappings(m => m
            .Map<TestType>(t => t
                .AutoMap()
                .Properties(p => p
                    // don't analyze ids when indexing,
                    // so they are indexed verbatim
                    .String(s => s
                        .Name(n => n.Id)
                        .NotAnalyzed()
                    )
                )
            )
        )
    );

    var testItem = new TestType { Id = Guid.NewGuid(), Name = "Test", Value = "10" };

    // now index our TestType instance
    var response = client.Index(testItem);
}

public class TestType
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Value { get; set; }
}

Take a look at the Automapping documentation for more examples of how to explicitly map a POCO for controlling norms, analyzers, multi_fields, etc.

Comments