When I try to create a suggester on an index using .net sdk I get an error.
I can create index successfully using .net SDK but when I try to add suggester I get an error.
My index code:
var index = new Index()
{
Name = "customeridex",
Fields = FieldBuilder.BuildForType<AutocompleteResponseDetail>(),
Suggesters = new List<Suggester>() {new Suggester()
{
Name="cg",
SourceFields= new string[] { "Title", "Description" }
}}
};
The error message I get:
'The request is invalid. Details: definition: One or more fields in suggester 'cg' are not defined as a field in the index. Fields: Title, Description.'
Although I have fields: Title and description in my index
Try this :
var definition = new Index()
{
Name = "customeridex",
Fields = FieldBuilder.BuildForType<AutocompleteResponseDetail>(),
Suggesters = new List<Suggester> {new Suggester("cg","Title", "Description") }
};
I have tested on my side and it works for me.
My bad, it was casing error. Above sourcefields need to be all small to match index schema.
Related
If I simply attempt to add a Group using the Kontent Management API (v2) to an existing Kontent type I get the following error (see code below which generates this error):
Validation errors: 511 Every element should have a correct content group reference when using groups
What is the process for adding a group via the Management API in this case using C#? I would assume that I need to add a group Reference to all the existing elements first, but how do I do that when I cannon add the group through the API? Can I create a valid Reference simply using a new ContentGroupModel() object before adding it to the actual type in Kontent?
Here is my existing code, which throws the above error:
var updatedType = await service.ModifyContentTypeAsync(
Reference.ById(existingContentType.Id),
new ContentTypeAddIntoPatchModel
{
Path = "/content_groups",
Value = new ContentGroupModel
{
Name = "New Group",
CodeName = "new_group"
}
}
);
using Kentico.Kontent.Management;
var client = new ManagementClient(new ManagementOptions
{
ApiKey = "<YOUR_API_KEY>",
ProjectId = "<YOUR_PROJECT_ID>"
});
var identifier = Reference.ById(Guid.Parse("0be13600-e57c-577d-8108-c8d860330985"));
// var identifier = Reference.ByCodename("my_article");
// var identifier = Reference.ByExternalId("my-article-id");
var response = await client.ModifyContentTypeAsync(identifier, new ContentTypeOperationBaseModel[]
{
new ContentTypeReplacePatchModel
{
Path = "/name",
Value = "A new type name"
},
new ContentTypeReplacePatchModel
{
Path = "/elements/codename:my_text_element/guidelines",
Value = "Here you can tell users how to fill in the element."
},
new ContentTypeAddIntoPatchModel
{
Path = "/elements",
Value = new TextElementMetadataModel
{
Name = "My title",
Guidelines = "Title of the article in plain text.",
ExternalId = "my-title-id",
},
},
new ContentTypeRemovePatchModel
{
Path = "/elements/id:0b2015d0-16ae-414a-85f9-7e1a4b3a3eae"
}
});
Refer - https://docs.kontent.ai/reference/management-api-v2#operation/modify-a-content-type
I was able to work it out. It turns out you can use the Codename of the new group, even before adding it in Kontent, as a reference. Then give that reference to the content_group property/path for existing elements in the model.
Here is the code I have now that adds the new Group and adds it to all existing elements dynamically:
using Kentico.Kontent.Management.Models.Shared;
using Kentico.Kontent.Management.Models.Types;
using Kentico.Kontent.Management.Models.Types.Patch;
//
// ...
//
// First, Get type from the client. Then ...
var elementCodenames = myType.Elements.Select(el => el.Codename);
// Create reference to the codename of the group to be created
var groupRef = Reference.ByCodename("new_group");
// Create the modify models
var modifyModels = new ContentTypeOperationBaseModel[] {
new ContentTypeAddIntoPatchModel
{
Path = "/content_groups", // Add to content_groups path
Value = new ContentGroupModel
{
Name = "New Group",
CodeName = "new_group" // Same codename as above
}
}
}
.Concat(
// Dynamically add new group, by ref, to existing elements
elementCodenames.Select(codename => new ContentTypeReplacePatchModel
{
Path = $"/elements/codename:{codename}/content_group",
Value = groupRef // Group reference created above from the codename
})
);
// Make call to add new group AND link group to elements in the one call
var response = await client.ModifyContentTypeAsync(myTypeIdentifier, modifyModels.ToArray());
Leaving out other details, like retrieving the existing type, but for reference here are the API Docs: https://docs.kontent.ai/reference/management-api-v2
i am using net 6.0.1 with asp.net mvc.
var node = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(node);
var client = new ElasticClient(setting);
var news = new News
{
NewsTitle = "TestTitle"
};
client.Index(news, idx => idx.Index("NewsTitle"));
var response = client.Get<News>(1, idx => idx.Index("NewsTitle"));
ElasticSearch is installed and running but when I try to run these lines of code then it does nothing. No index is created.
There's a few things to consider
client.Index(news, idx => idx.Index("NewsTitle")); doesn't check the response of the index document request.
It's a good idea to check the response to see if it succeeded - NEST
has a convenient .IsValid property on all responses that has
semantics for considering if the response is valid
var response = client.Get<News>(1, idx => idx.Index("NewsTitle")); attempts to get a document from the "NewsTitle" index with an id of 1, but the document just indexed does not have an id, so Elasticsearch will generate a random one when it indexes the document.
NEST has a convention where if the POCO to index has an Id property, it will use this as the id of the document. So, if News class is modified to contain an int Id property, and the instance indexed is assigned an Id property value of 1, the get request will return the indexed document.
I am trying to bulk a collection of elements inside an index of ElasticSearch using NEST inside a .NET Core application.
Currently what I have is working, and the elements are saved, but Is not saved where I try to do
My client creation:
protected ElasticClient GetClient()
{
var node = new Uri("http://localhost:9200/");
var settings = new ConnectionSettings(node)
.DefaultIndex("TestIndex")
.PrettyJson(true);
return new ElasticClient(settings);
}
Here is how I create the descriptor for bulk all the data
protected BulkDescriptor GenerateBulkDescriptor<T>(IEnumerable<T> elements, string indexName) where T: class, IIndexable
{
var bulkIndexer = new BulkDescriptor();
foreach (var element in elements)
bulkIndexer.Index<T>(i => i
.Document(element)
.Id(element.Id)
.Index(indexName));
return bulkIndexer;
}
Finally, once I have this, here is how I index the data
var descriptor = GenerateBulkDescriptor(indexedElements, "indexed_elements");
var response = GetClient().Bulk(descriptor);
But, If I see how It's stored in the Elastic index using this, that is what I have:
How can I know if is created under TestIndex index? Because as far as I can see, there is just one index created
Thank you a lot in advance
When defining the index operations on the BulkDescriptor, you are explicitly setting the index to use for each operation
foreach (var element in elements)
bulkIndexer.Index<T>(i => i
.Document(element)
.Id(element.Id)
.Index(indexName));
where indexName is "indexed_elements". This is why all documents are indexed into this index and you do not see any in "TestIndex".
The Bulk API allows multiple operations to be defined, which may include indexing documents into different indices. When the index is specified directly on an operation, that will be the index used. If all index operations on a Bulk API call are to take place against the same index, you can omit the index on each operation and instead, specify the index to use on the Bulk API call directly
var defaultIndex = "default_index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(settings);
var people = new []
{
new Person { Id = 1, Name = "Paul" },
new Person { Id = 2, Name = "John" },
new Person { Id = 3, Name = "George" },
new Person { Id = 4, Name = "Ringo" },
};
var bulkResponse = client.Bulk(b => b
.Index("people")
.IndexMany(people)
);
which sends the following request
POST http://localhost:9200/people/_bulk
{"index":{"_id":"1","_type":"person"}}
{"id":1,"name":"Paul"}
{"index":{"_id":"2","_type":"person"}}
{"id":2,"name":"John"}
{"index":{"_id":"3","_type":"person"}}
{"id":3,"name":"George"}
{"index":{"_id":"4","_type":"person"}}
{"id":4,"name":"Ringo"}
Note that the URI is /people/bulk and that each JSON object representing an operation does not contain an "_index".
If you omit the .Index() on Bulk API call, it will use the DefaultIndex configured on ConnectionSettings:
var bulkResponse = client.Bulk(b => b
.IndexMany(people)
);
which yields
POST http://localhost:9200/_bulk
{"index":{"_id":"1","_index":"default_index","_type":"person"}}
{"id":1,"name":"Paul"}
{"index":{"_id":"2","_index":"default_index","_type":"person"}}
{"id":2,"name":"John"}
{"index":{"_id":"3","_index":"default_index","_type":"person"}}
{"id":3,"name":"George"}
{"index":{"_id":"4","_index":"default_index","_type":"person"}}
{"id":4,"name":"Ringo"}
You can also specify a default index to use for a given POCO type on ConnectionSettings with DefaultMappingFor<T>(), where T is your POCO type.
After som tests and attemps, I have found a solution.
First of all, it was a problem with the index configured, once I set it in lower case, the index was working fine indexing data inside.
Then, I had the problem of index data in a specific "path" inside the same index, finalyy I found the Type solution from NEST, taking also advantage of the DefaultMappingFor suggested by Russ in the previous answer.
Client definition:
var node = new Uri(_elasticSearchConfiguration.Node);
var settings = new ConnectionSettings(node)
.DefaultMappingFor<IndexedElement>(m => m
.IndexName(_elasticSearchConfiguration.Index)
.TypeName(nameof(IndexedElement).ToLower()))
.PrettyJson(true)
.DisableDirectStreaming();
var client = new ElasticClient(settings);
Then, the BulkDescriptior creation:
var bulkIndexer = new BulkDescriptor();
foreach (var element in elements)
bulkIndexer.Index<IndexedElement>(i => i
.Document(element)
.Type(nameof(IndexedElement).ToLower()))
.Id(element.Id)
);
And finally, data bulk:
client.Bulk(bulkIndexer);
Now, If I perform a call to the index, I can see this
{
"testindex": {
"aliases": {},
"mappings": {
"indexedelement": {
[...]
}
Thank you Russ for your help and for who have had a look to the post.
UPDATE
Finally, it seems that the unique problem was regarding the default index, that it must be lowercase, so, specify the type with the name of the POCO itself is not neccesary, like #RussCam has truly detected in comments above. After changing thedefault index to lowercase, all the different possibilities worked fine.
Thank you all again
I use Nest client to use ElasticSearch .I want to search in ElasticSearch :
SearchRequest countRequest = new SearchRequest
{
//Somthing
};
client.Search<Post>(countRequest);
On other hand :
client.Search<Post>(s=>s.Index("IndexName").Query(...))
How i can set index name by SearchRequest class search ?
This is for those using newer versions of NEST. In 2.0.1, I am unable to find the Indices property in SearchRequest. However, you can pass them in through the constructor:
var request = new SearchRequest<Post>("IndexName", "TypeName");
I map the index and type on the ConnectionSettings like so.
ConnectionSettings settings = new ConnectionSettings("url");
settings.MapDefaultTypeIndices(t => t.Add(typeof(Post), "IndexName"));
settings.MapDefaultTypeNames(t => t.Add(typeof(Post), "TypeName"));
Other ways to tell NEST the index and type:
client.Search<Post>(s => s.Index("IndexName").Type("TypeName").From(0));
or apply the ElasticsearchTypeAttribute on the type.
[ElasticsearchType(Name = "TypeName")]
public class Post{ }
SearchRequest contains an Indices property, so that you can specify multiple indices to search across. In your case, you could just pass the single index like so:
var request = new SearchRequest
{
Indices = new IndexNameMarker[] { "IndexName" }
};
Another option would be to map your Post type to the index it belongs to, and use the typed SearchRequest<T> to let NEST infer the index name.
I was trying to solve a bit different task with ES v5 (json request was pushed from the file) but also had the same problem with setting the indexName. So, my solution was to add index querystring parameter. Using this in integration tests:
public static class ElasticSearchClientHelper
{
public static ISearchResponse<T> SearchByJson<T>(this IElasticClient client, string json, string indexName, Dictionary<string, object> queryStringParams = null) where T : class
{
var qs = new Dictionary<string, object>()
{
{"index", indexName}
};
queryStringParams?.ForEach(pair => qs.Add(pair.Key, pair.Value));
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
var searchRequest = client.Serializer.Deserialize<SearchRequest>(stream);
((IRequestParameters)((IRequest<SearchRequestParameters>)searchRequest).RequestParameters).QueryString = qs;
return client.Search<T>(searchRequest);
}
}
}
I'm trying to create an entity in CRM 2011 (not an out of the box kind, but what in CRM 4 would have been called a DynamicEntity... one with my custom attributes). The code below gives me this error and I'm not sure why. This exact same code works if I remove the new_accounttype attribute and try to use another custom attribute.
CRM seems to have taken issue with the "OptionSetValue" being set as the value for that key value pair. new_accounttype is a picklist (or OptionSet in CRM 2011) and that value of 100000003 was pulled from the front end so it's a valid value.
Error: A validation error occurred. The value of 'new_accounttype' on
record of type 'account' is outside the valid range.
What am I doing wrong?
public static void CreateAccount(string accountName, string accountType)
{
//Create properties
KeyValuePairOfstringanyType[] attributes = new KeyValuePairOfstringanyType[2];
attributes[0] = new KeyValuePairOfstringanyType() { key = "name", value = accountName ?? "" };
attributes[1] = new KeyValuePairOfstringanyType() { key = "new_accounttype", value = new OptionSetValue() { Value = 100000003 } };
////Create DynamicEntity
Entity accountToCreate = new Entity();
accountToCreate.LogicalName = "account";
accountToCreate.Attributes = attributes;
try
{
service.Create(accountToCreate);
}
}
I agree that what you have should work fine. This can only mean that the value isn't published or is incorrect. As #glosrob mentions, check that the changes are actually published. Confirm these values by looking at the published form and seeing if your new value is present (and perhaps double check by using IE Developer Tools - hit F12 - and confirm that the value in the select>option object in the HTML contains the integer you expect).
As an aside, your code looks more complex than necessary (IMHO!). I believe this is easier to read an no less efficient:
Try this:
public static void CreateAccount(string accountName, string accountType)
{
////Create DynamicEntity
Entity accountToCreate = new Entity();
accountToCreate.LogicalName = "account";
accountToCreate.Attributes = attributes;
//Append properties
accountToCreate.Attributes.Add("name", accountName ?? "" );
accountToCreate.Attributes.Add("new_accounttype", new OptionSetValue(100000003);
try
{
service.Create(accountToCreate);
}
}
Give this a shot: key = "new_accounttype", value = new OptionSetValue(100000003)