ErvinsA
ErvinsA

Reputation: 1

ELASTICSEARCH NEST Automap string override either that string fields receive a keyword normalizer or something else, for case insensitive search

Im very unfamiliar with ElasticSearch, but basically I've been trying to figure out how to make all database fields that are string to be searchable case insensitively. As currently the Automap creates them with text fields and keyword textfields and the whole logic for searching is using keywords, and doesn't look like it is changeable, due to some business logic.

I am trying to understand how can I add a lowercase normalizer when all of the indexes are created and mapped. Here is the code as it is.

        public void CheckIndexes(IServiceCollection services)
    {
        var sp = services.BuildServiceProvider();
        var elastiClient = sp.GetService<ElasticSearchClient>();

        var indexes = Indexes.List.Select(x => x.IndexName);

        foreach (var index in Indexes.List)
        {
            if (!elastiClient.Client.Indices.Exists(index.IndexName).Exists)
            {
                elastiClient.
                    Client.
                    Indices.
                    Create(index.IndexName, x => x
                        .Settings(b => b
                            .NumberOfShards(1)
                                .NumberOfReplicas(0))
                                    .Map<BaseEntity>(m=>m
                                        .AutoMap(index.EntityType)));
            }
        }
    }
}

I tried adding this, but then I am receiving an exception "{"Sequence contains no elements"}"

                    elastiClient
                    .Client
                    .Indices
                    .Create(index.IndexName, c => c
                        .Settings(s => s
                            .Analysis(a => a
                                .Normalizers(n => n
                                    .Custom("lowercase", cn => cn
                                        .Filters("lowercase")
                                    )
                                )
                            )
                        )
                        .Map<BaseEntity>(m => m
                            .AutoMap(index.EntityType)
                            .Properties(p => p
                                .Text(t => t
                                    .Name(n => n)
                                    .Fields(f => f
                                        .Keyword(k => k
                                            .Name("keyword")
                                            .IgnoreAbove(256)
                                        )
                                        .Keyword(k => k
                                            .Name("keyword_lowercase")
                                            .Normalizer("lowercase")
                                            .IgnoreAbove(256)
                                        )
                                    )
                                )
                            )
                        )
                    );

Upvotes: 0

Views: 437

Answers (1)

LeBigCat
LeBigCat

Reputation: 1770

Using nest you can create it with flent or attributes.

With attributes, create a class like this:

[ElasticsearchType(RelationName = "geopolitic", IdProperty = "code")]
    public class GeoPolitic
    {
        public GeoPolitic(string id) {
            Code = id;
        }

        [Keyword(Name = "Code")]
        public string Code { get; }


        [Text(Name = "NameSearcher", SearchAnalyzer = "full_name", Analyzer = "partial_name")]
        public string NameSearcher { get; set; }

        [Keyword(Name = "CntPlaceType")]
        public int PlaceType { get; set; }

        [Keyword(Name = "CntCd")]
        public string CntCd { get; set; }

        [Keyword(Name = "CntCd2")]
        public string CntCd2 { get; set; }

        [Keyword(Name = "CntNumeric")]
        public int CntNumeric { get; set; }

        [Keyword(Index = false)]
        public string NoIndexedField{ get; set; }

        public int? nullableIntIndexedField{ get; set; }
    }

To create your custom mapping (and the index) call

public void SetMapping(string index)
        {

            CustomAnalyzer partialName = new CustomAnalyzer
            {
                Filter = new List<string> { "lowercase", "name_ngrams", "standard", "asciifolding" },
                Tokenizer = "standard"
            };

            CustomAnalyzer fullName = new CustomAnalyzer
            {
                Filter = new List<string> { "standard", "lowercase", "asciifolding" },
                Tokenizer = "standard"
            };

            var res = Client.Indices.Create(index, c => c
               .Map<GeoPolitic>(m => m
                    .AutoMap()
            )
            .Settings(
                s =>
                    s.Analysis(
                        a =>
                            a.TokenFilters(
                                tf => tf.EdgeNGram("name_ngrams", eng => eng.MaxGram(20).MinGram(1).Side(EdgeNGramSide.Front))
                            )
                            .Analyzers(
                                an =>
                                    an.Custom("partial_name", cad =>
                                            cad.Tokenizer("standard").Filters(new string[] {
                                                "lowercase",
                                                "asciifolding",
                                                "name_ngrams"
                                            }))
                                        .Custom("full_name", cad =>
                                            cad.Tokenizer("standard").Filters(new string[] {
                                                "lowercase",
                                                "asciifolding"
                                            }))
                        )
                    )
            )
            );
        }

You can also create it using fluent api: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/fluent-mapping.html

Upvotes: 2

Related Questions