Assign types to a specific index using NEST2 - nest

I would like to be able to set up some sort of mapping using the NEST2 client so that different types are automatically put in a defined index. Is this possible?
I've tried to map types like this:
client.Map<A>(m => m.Index("index1"));
client.Map<B>(m => m.Index("index2"));
And then index them like this:
client.Index(new SomethingThatGoesToTheDefaultIndex());
client.Index(new A());//Should end up in index1
client.Index(new B());//Should end up in index2
But everything ends up in the default index and not the set index. Do I need to give the required index every time I store data, or is it possible to set up a defined index per type?

You can pass index name with help of second parameter in .Index(..) method.
Just like this:
client.Index(new A(), descriptor => descriptor.Index("index1"));
client.Index(new B(), descriptor => descriptor.Index("index2"));
UPDATE
MapDefaultTypeIndices will help you to specify default index name for type.
var settings = new ConnectionSettings()
.MapDefaultTypeIndices(dictionary =>
{
dictionary.Add(typeof (A), "index1");
dictionary.Add(typeof (B), "index2");
});
var client = new ElasticClient(settings);
Hope it helps.

Related

Get and manipulate data from elasticsearch

I am new to elasticsearch so I will need some help. Unfortunately, I didnt found the answer in other topics here on SO.
I have some .net core application which I inherited and now there is a need to implement some changes.
I already have a method of getting data from elasticsearch, but after getting them, I am not sure how to change it and use it in application.
To be precise, I need to parse first and last name and to remove special characters, specific serbian latin letters like "šđžčć" etc... I already have a method for this parsing written but not sure how to call it...
So, my question is can I and how can I do this?
What I have now is the following:
var result = await _elasticClient.SearchAsync<CachedUserEntity>(
s =>
s.Index(_aliasName)
.Query(q => andQuery));
CachedUserEntity, among others, contains property about FirstName and LastName.
Inside results.Documents, I am getting the data about FirstName and LastName from elasticsearch, but I am not sure how to access it in order to update it via aformentioned NameParser ...
Sorry if the question is too easy, not to say stupid :)
I wont use updateByQuery here, for some reasons. I would scroll on documents (i use matchAll on my exemple, you obviously need to replace it with your query), or, if you dont know how to identify documents to update, only update usefull documents in UpdateManyWithIndex/UpdateManyPartial function.
For performance, we have to update severals documents at once, so we use bulk/updateMany function.
You can use both solution, the classic update, or the second (partial update) with an object containing the targeteds fields.
On server sides, both solutions will have the same cost / performance.
var searchResponse = Client.Search<CachedUserEntity>(s => s
.Query(q => q
MatchAll()
)
.Scroll("10s")
);
while (searchResponse.Documents.Any())
{
List<CachedUserEntity> NewSearchResponse = RemoveChar(searchResponse);
UpdateManyWithIndex<CachedUserEntity>(NewSearchResponse, _aliasName);
searchResponse = Client.Scroll<Project>("2h", searchResponse.ScrollId);
}
public void UpdateManyWithIndex<C>(List<C> obj, string index) where C : class {
var bulkResponse = Client.Bulk(b => b
.Index(index).Refresh(Elasticsearch.Net.Refresh.WaitFor) // explicitly provide index name
.UpdateMany<C>(obj, (bu, d) => bu.Doc(d)));
}
Or, using partial update object
Note: in this case Indix is already set on my client (add .index if needed)
var searchResponse = Client.Search<CachedUserEntity>(s => s
.Query(q => q
MatchAll()
)
.Scroll("2h")
);
while (searchResponse.Documents.Any())
{
List<object> listPocoPartialObj = GetPocoPartialObjList(searchResponse);
UpdateManyPartial(listPocoPartialObj);
searchResponse = Client.Scroll<Project>("2h", searchResponse.ScrollId);
}
private List<object> GetPocoPartialObjList(List<CachedUserEntity> cachedList) {
List<object> listPoco = new List<object>();
//note if you dont have cachedList.Id, take a look at result.source, comments if needed
foreach (var eltCached in cachedList) {
listPoco.Add( new object() { Id = cachedList.Id, FirstName = YOURFIELDWITHOUTSPECIALCHAR, LastName = YOURSECONDFIELDWITHOUTSPECIALCHAR});
}
return listPoco;
}
public bool UpdateManyPartial(List<object> partialObj)
{
var bulkResponse = Client.Bulk(b => b
.Refresh(Elasticsearch.Net.Refresh.WaitFor)
.UpdateMany(partialObj, (bu, d) => bu.Doc(d))
);
if (!bulkResponse.IsValid)
{
GetErrorMsgs(bulkResponse);
}
return (bulkResponse?.IsValid == true);
}

Terraform function lookup within lookup

I am trying to use Terraform function lookup and then lookup to fetch the values and then add into the conditional loop based on the value like below - For creating s3 bucket server side encryption
Below is var.tf
variable "encryption" {
type = map
default = {
"keyMap" = "SSE-S3"
"kmsType" = "aws-kms"
"keyNull" = null
}
}
Now I want to use local.tf with below code to get "SSE-S3" value like below
encryption_type = lookup(var.encryption, "default", null) == null ? null : lookup(var.encryption.default, "keyMap", null)
Just wonder above my logic will fetch the value for encryption_type is "SSE-S3"
Any help is appreciated. Thanks in advance.
You don't have to lookup "default". The default inside a variable definitions is just the default value of that variable. Your current code is actually invalid because a lookup on "default" is never going to work. It's also not clear what your "keyMap" lookup is doing, since there is no property in your example named "keyMap".
Your code could be corrected and shortened to the following:
encryption_type = lookup(var.encryption, "keyType", null)
or just
encryption_type = var.encryption["keyType"]

Ordering a query by the string length of one of the fields

In RavenDB (build 2330) I'm trying to order my results by the string length of one of the indexed terms.
var result = session.Query<Entity, IndexDefinition>()
.Where(condition)
.OrderBy(x => x.Token.Length);
However the results look to be un-sorted. Is this possible in RavenDB (or via a Lucene query) and if so what is the syntax?
You need to add a field to IndexDefinition to order by, and define the SortOption to Int or something more appropriate (however you don't want to use String which is default).
If you want to use the Linq API like in your example you need to add a field named Token_Length to the index' Map function (see Matt's comment):
from doc in docs
select new
{
...
Token_Length = doc.TokenLength
}
And then you can query using the Linq API:
var result = session.Query<Entity, IndexDefinition>()
.Where(condition)
.OrderBy(x => x.Token.Length);
Or if you really want the field to be called TokenLength (or something other than Token_Length) you can use a LuceneQuery:
from doc in docs
select new
{
...
TokenLength = doc.Token.Length
}
And you'd query like this:
var result = session.Advanced.LuceneQuery<Entity, IndexDefinition>()
.Where(condition)
.OrderBy("TokenLength");

RavenDB: static index casting and sorting issue

I have a problem with RavenDB indexing.
Simple query looks like this:
var values =
myCollection.Query.Where(w =>
w.MyId == MyId &&
w.IsReady == false &&
w.IsDeleted &&
w.Rate > 0)
During execution Raven creates dynamic index:
from doc in docs.MyCollection
select new { Rate = doc.Rate, IsReady = doc.IsReady, IsDeleted = doc.IsDeleted, MyId = doc.MyId }
with extra options:
Field -> Rate;
Storage -> No;
Indexing -> Default;
Sort -> Double;
Field Rate has decimal type.
Problem:
I wanted to add static index, but when I specified index like this:
public class MyIndex : AbstractIndexCreationTask<MyCollection> {
public MyIndex () {
Map = d => d.Select(s => new { Rate = s.Rate, IsReady = s.IsReady, IsDeleted = s.IsDeleted, MyId = s.MyId });
Sort(x => x.Rate, SortOptions.Double);
}
}
Raven is creating index slightly different:
from doc in docs.MyCollection
select new { Rate = (decimal)doc.Rate, IsReady = doc.IsReady, IsDeleted = doc.IsDeleted, MyId = doc.MyId }
with extra options:
Field -> Rate;
Storage -> No;
Indexing -> Default;
Sort -> Double;
The only difference is that I have casting in static index, because my field type is decimal and I'm using Double sort option.
Because of that Raven is not using my static index but instead creates dynamic one every time query is being executed.
I tried to do some casting inside Sort() but then index has not been created at all. One way to overcome this issue is to manually modify static index from management console after it was created, but it's not good solution.
Any ideas how to deal with that?
Thanks.
Edit:
Another example:
Type of field DateTime and querying using DateTime values as predicates (greater than / less than). Raven in dynamic index creation picks String as a SortOption, and when I try to prepare static index I get casting issue.
You can use the IDocumentSession.Query(string indexName, [bool isMapReduce]) or the IDocumentSession.Query<TResult, TIndexCreator>() overloads to explicitly specify a static index. So in your specific case, either IDocumentSession.Query<MyCollection, MyIndex>() or IDocumentSession.Query("MyIndex").

What return value to use to match two different kinds of Types

I'm using LINQ towards my MSSQL database. I have the TypeOfMetaData-table, the UserMetaData-table and the MetaDataHasType-table that has foreign-keys from the TypeOfMetaData- and the UserMetaData-table. What I need to do a method to get all MetaData and Types and return them. The problem is that I don't know what kind of return value I should use to be able to match the correct rows together.
Thanks for the help,
wardh
You could use an Anonymous Type (var) to store the result:
var result =
yourDataContext
.UserMetaData_Table
.Select(
userMetaData =>
new
{
UserMetaData = userMetaData,
Types = userMetaData.MetaDataHasTypes.Select(types => types.TypeOfMetaData),
})
.ToArray();
If this isn't what you want, could you update you question to with an example of the data context and the classes you have and what you have tried so far.