How to add conditional properties for index creation in elasticsearch nest? - elasticsearch

I want to create index with some condition,like with querycontainer to add conditional filters.
PropertiesDescriptor<object> ps = new PropertiesDescriptor<object>();
if (condition)
{
ps.Text(s => s.Name(name[1]));
}
if(condition)
{
ps.Number(s => s.Name(name[1]));
}
if (!_con.client.Indices.Exists(indexname).Exists)
{
var createIndexResponse = _con.client.Indices.Create(indexname, index => index.Settings(s => s.NumberOfShards(1).NumberOfReplicas(0))
.Map(m=>m.Properties(ps)));
}
But i receive following error, can you guide me how to acheive this.
cannot convert from 'Nest.PropertiesDescriptor<object>' to 'System.Func<Nest.PropertiesDescriptor<object>, Nest.IPromise<Nest.IProperties>>'

You are almost there, just change Properties part to m.Properties(p => ps).
_con.client.Indices.Create(indexname,
index => index.Settings(s => s.NumberOfShards(1).NumberOfReplicas(0)).Map(m=>m.Properties(p => ps)));
Hope that helps.

Related

Change ElasticSearch track_total_hits in NEST

I was running thought examples of ElasticSearch, and read this link that says that there is a default set at 10,000, which also can be changed on the search calls, like on this example
GET twitter/_search
{
"track_total_hits": 100,
"query": {
"match" : {
"message" : "Elasticsearch"
}
}
}
The problem is, I'm trying to do the same on NEST, but I don't manage to replicate it. The only thing similar that I found, only accept a Boolean value and not a number. It is possible to change the total through NEST?
Here is the code that I tried:
var results = elasticClient.Search<MyClass>(s => s
.Query(q => q.QueryString(q2 => q2.Query(readLine)
.Fields(f => f.Field(p => p.MyField)))).TrackTotalHits(true));
As stated by #russcam here at the moment you can do it via casting ISearchRequest to IRequest<SearchRequestParameters>:
var client = new ElasticClient();
var searchResponse = client.Search<Document>(s =>
{
IRequest<SearchRequestParameters> request = s;
request.RequestParameters.SetQueryString("track_total_hits", 1000);
return s;
});
It will apply it as querystring parameter

Setting the Elasticsearch routing_partition_size using NEST

I'm using NEST to create an index in Elasticsearch 5.5. I need to update the index.routing_partition_size setting on index creation but don't see that setting in the in CreateIndexDescriptor object. How can I specify what this value is in NEST?
My settings currently looks like this:
return createIndexSelector
//add analyzers and tokenizers
.Settings(s => s
.NumberOfReplicas(2)
.NumberOfShards(40)
.Setting("refresh_interval", 10)
.Analysis(a => a
.Analyzers(az => az
.Custom("str_search_analyzer", c1 => GetCustomSearchAnalyzer())
.Custom("str_index_analyzer", c2 => GetCustomNgramAnalyzer()))
.Tokenizers(tz => tz
.NGram("autocomplete_ngram_tokenizer", ng => GetCustomAutoCompleteTokenizer()))))
//add mappings for invoice and contact doc types
.Mappings(m => m
.Map<DocType>(mDocType => mDocType .Properties(DocType.AddAllMappings)));
Assuming you are using NEST 5.x, it's under IndexSettingsDescriptor
var createIndexResponse = await client.CreateIndexAsync("index", c => c
.Settings(s => s.RoutingPartitionSize(10)));
Which produces the following request
{
"settings": {
"index.routing_partition_size": 10
}
}
Hope that helps.

LINQ SelectMany equivalent in Scala

I have some quite simple .NET logic that I'm transplanting into a Scala codebase, and I don't really know the first thing about Scala. It includes a LINQ query that groups a collection of tagged objects by making use of an anonymous type projection to flatten and join, followed by grouping, eg:
var q = things.SelectMany(t => t.Tags, (t, tag) => new { Thing = t, Tag = tag })
.GroupBy(x => x.Tag, x => x.Thing);
In Scala it looks like flatMap might be of use, but I can't figure out how to combine it with groupBy via an anonymous.
Is this kind of thing a lot more complicated in Scala, or am I missing something simple?
UPDATE:
I ended up going with:
things.flatMap(t => t.Tags.map(x => (x,t))).groupBy(x => x._1)
and then of course later on when I access a value in the map I need to do:
.map(x => x._2)
to get the groups out of the tuple.
Simple when you know how!
Seems to me you want to do something like.
case class Tag(tag:String)
case class Thing(Tags : Seq[Tag])
val things :Seq[Thing] = Seq(Thing(Seq(Tag(""))))
val q = things.map {
thing => new {
val Thing = thing
val Tags = thing.Tags
}
}.flatMap {
thingAndTags => thingAndTags.Tags.map {
tag => new {
val Thing = thingAndTags.Thing
val Tag = tag
}
}
}. groupBy {
thingAndTag => thingAndTag.Tag
}.map {
tagAndSeqOfThingAndTags =>
tagAndSeqOfThingAndTags._1 -> tagAndSeqOfThingAndTags._2.map(x => x.Thing)
}
But in Scala anonymous objects are not really common but you can use Tuple2[T1,T2] instead of all the new { val ...}s,
val q = things.map {
thing => ( thing->thing.Tags)
}.flatMap {
thingAndTags => thingAndTags._2.map {
tag => (thingAndTags._1, tag)
}
}.groupBy {
thingAndTag => thingAndTag._2
}.map {
tagAndSeqOfThingAndTags =>
tagAndSeqOfThingAndTags._1 -> tagAndSeqOfThingAndTags._2.map(x => x._1)
}
its just a little confusing with all the ._1s and ._2s

example of how to use synonyms in nest

i haven't found a solid example on how to create and use synonyms using Nest for Elasticsearch. if anyone has one it would be helpful.
my attempt looks like this, but i don't know how to apply it to a field.
var syn = new SynonymTokenFilter
{
Synonyms = new [] { "pink, p!nk => pink", "lil, little", "ke$ha, kesha => ke$ha" },
IgnoreCase = true,
Tokenizer = "standard"
};
client.CreateIndex("myindex", i =>
{
i
.Analysis(a => a.Analyzers(an => an
.Add("fullTermCaseInsensitive", fullTermCaseInsensitive)
)
.TokenFilters(x => x
.Add("synonym", syn)
)
)
...
it's very simple :)
you will need to define first the Synonym filter the you can use it in your custom Analyzer...where you can add also other type of filters.
Small example :
.Analysis(descriptor => descriptor
.Analyzers(bases => bases
.Add("folded_word", new CustomAnalyzer()
{
Filter = new List<string> { "icu_folding", "trim", "synonym" },
Tokenizer = "standard"
}
)
)
.TokenFilters(i => i
.Add("synonym", new SynonymTokenFilter()
{
SynonymsPath="analysis/synonym.txt",
Format = "Solr"
}
)
)
Then you can use the custom analyzer in the mapping part
Assuming your fullTermCaseInsensitive analyzer is custom, you need to add your synonym filter to it:
var fullTermCaseInsensitive = new CustomAnalyzer()
{
.
.
.
Filter = new string[] { "syn" }
};
And upon creating your index, you can add a mapping and apply the fullTermCaseInsensitive analyzer to your field(s):
client.CreateIndex("myindex", c => c
.Analysis(a => a
.Analyzers(an => an.Add("fullTermCaseInsensitive", fullTermCaseInsensitive))
.TokenFilters(tf => tf.Add("syn", syn)))
.AddMapping<MyType>(m => m
.Properties(p => p
.String(s => s.Name(t => t.MyField).Analyzer("fullTermCaseInsensitive")))));

Need concrete documentation / examples of building complex index using NEST ElasticSearch library

I would like to use the NEST library's Fluent interface to create an index, which involves setting up custom filters, analyzers, and type mappings. I would like to avoid decorating my classes with NEST-specific annotations.
I have seen the documentation at http://nest.azurewebsites.net/indices/create-indices.html and http://nest.azurewebsites.net/indices/put-mapping.html. This documentation, while showing some examples, is not complete enough to help me figure out how to use the Fluent API to build some complex indexing scenarios.
I have found the tutorial at http://euphonious-intuition.com/2012/08/more-complicated-mapping-in-elasticsearch/ to be quite helpful; some code showing how to build the filters, analyzers and mappings in this tutorial via the NEST Fluent interface in place of the straight JSON would be a great answer to this question.
The more specific you can be with your question the better the answers you receive will be. Nevertheless, here is an index that sets up an analyzer (with filter) and tokenizer (EdgeNGram) and then uses them to create an autocomplete index on the Name field of a Tag class.
public class Tag
{
public string Name { get; set; }
}
Nest.IElasticClient client = null; // Connect to ElasticSearch
var createResult = client.CreateIndex(indexName, index => index
.Analysis(analysis => analysis
.Analyzers(a => a
.Add(
"autocomplete",
new Nest.CustomAnalyzer()
{
Tokenizer = "edgeNGram",
Filter = new string[] { "lowercase" }
}
)
)
.Tokenizers(t => t
.Add(
"edgeNGram",
new Nest.EdgeNGramTokenizer()
{
MinGram = 1,
MaxGram = 20
}
)
)
)
.AddMapping<Tag>(tmd => tmd
.Properties(props => props
.MultiField(p => p
.Name(t => t.Name)
.Fields(tf => tf
.String(s => s
.Name(t => t.Name)
.Index(Nest.FieldIndexOption.not_analyzed)
)
.String(s => s
.Name(t => t.Name.Suffix("autocomplete"))
.Index(Nest.FieldIndexOption.analyzed)
.IndexAnalyzer("autocomplete")
)
)
)
)
)
);
There is also a fairly complete mapping example in NEST's unit test project on github.
https://github.com/elasticsearch/elasticsearch-net/blob/develop/src/Tests/Nest.Tests.Unit/Core/Map/FluentMappingFullExampleTests.cs
Edit:
To query the index, do something like the following:
string queryString = ""; // search string
var results = client.Search<Tag>(s => s
.Query(q => q
.Text(tq => tq
.OnField(t => t.Name.Suffix("autocomplete"))
.QueryString(queryString)
)
)
);

Resources