Reputation: 1
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
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