Я использую ElarsticSearch 7.7 и NEST 7.7 и пытаюсь использовать массовую загрузку Elasti c Search 7. У меня есть основная модель и одна вложенная модель. Когда я загружаю список продуктов, я получаю сообщение об ошибке ниже.
# Invalid Bulk items:
operation[0]: update returned 400 _index: jm-dev-products _type: _doc _id: 0 _version: 0 error: Type: mapper_parsing_exception Reason: "object mapping for [associatedProducts.categoryIds] tried to parse field [null] as object, but found a concrete value"
operation[1]: update returned 400 _index: jm-dev-products _type: _doc _id: 0 _version: 0 error: Type: mapper_parsing_exception Reason: "object mapping for [availableStores] tried to parse field [null] as object, but found a concrete value"
operation[2]: update returned 400 _index: jm-dev-products _type: _doc _id: 0 _version: 0 error: Type: mapper_parsing_exception Reason: "object mapping for [availableStores] tried to parse field [null] as object, but found a concrete value"
Я упомянул Список также как [Вложенный]. Но я видел сообщение, в котором говорится, что этот список также упоминается как [Число].
Я доказываю большую часть своего кода, потому что его может использовать любой.
Это родительская модель, и она имеет AssociatedProducts как вложенные.
[ElasticsearchType(RelationName = "searchproduct")]
public class ElasticIndexGroupProduct
{
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int Id { get; set; }
[Date]
public DateTime IndexDate { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int ProductId { get; set; }
[Text]
public string PartNumber { get; set; }
[Text]
public string Name { get; set; }
[Text]
public string MetaKeywords { get; set; }
[Text]
public string MetaDescription { get; set; }
[Text]
public string MetaTitle { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool LimitedToStores { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> AvailableStores { get; set; }
[Text]
public string ShortDescription { get; set; }
[Text]
public string FullDescription { get; set; }
[Text]
public string SeName { get; set; }
[Nested]
[PropertyName("associatedProducts")]
public IList<ElasticIndexAssociatedProduct> AssociatedProducts { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> AssociatedProductIds { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool StockAvailability { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int DeliveryDateId { get; set; }
[Text]
public string DeliveryDateName { get; set; }
[Text]
public string CategoryName { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int CategoryId { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> CategoryIdsLimitToStore { get; set; }
[Text]
public string CategoryParentNamesStr { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> CategoryIds { get; set; }
[Text]
public string CategoryIdsStr { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool IsPublishedCategory { get; set; }
[Text]
public string ManufacturerNumber { get; set; }
[Text]
public string ManufacturerName { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int ManufacturerId { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool ManufacturerLimitToStore { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool IsPublishedManufacturer { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public decimal Price { get; set; }
[Text]
public string VendorName { get; set; }
[Text]
public string VendorSeName { get; set; }
[Text]
public string ProductPictureUrl { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool HasImage { get; set; }
}
это вложенная модель
[ElasticsearchType]
public class ElasticIndexAssociatedProduct
{
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int ProductId { get; set; }
[Text]
public string PartNumber { get; set; }
[Text]
public string Name { get; set; }
[Text]
public string MetaKeywords { get; set; }
[Text]
public string MetaDescription { get; set; }
[Text]
public string MetaTitle { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool LimitedToStores { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> AvailableStores { get; set; }
[Text]
public string ShortDescription { get; set; }
[Text]
public string FullDescription { get; set; }
[Text]
public string SeName { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool StockAvailability { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int DeliveryDateId { get; set; }
[Text]
public string DeliveryDateName { get; set; }
[Text]
public string CategoryName { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int CategoryId { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> CategoryIdsLimitToStore { get; set; }
[Text]
public string CategoryParentNamesStr { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public List<int> CategoryIds { get; set; }
[Text]
public string CategoryIdsStr { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool IsPublishedCategory { get; set; }
[Text]
public string ManufacturerNumber { get; set; }
[Text]
public string ManufacturerName { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int ManufacturerId { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool ManufacturerLimitToStore { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool IsPublishedManufacturer { get; set; }
[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public decimal Price { get; set; }
[Text]
public string VendorName { get; set; }
[Text]
public string VendorSeName { get; set; }
[Text]
public string ProductPictureUrl { get; set; }
[Boolean(NullValue = false, Store = true)]
public bool HasImage { get; set; }
[Text]
public string Specification { get; set; }
}
Это методы привязки данных
public static class IndexProductMappingExtension
{
public static async Task<ElasticIndexGroupProduct> ToIndexModel(this ElasticIndexGroupProductEntity model, JM_Core_ObjectContext jmContext, IDataProvider dataProvider, string imageUrlPrefix)
{
if (model == null)
return null;
var entity = new ElasticIndexGroupProduct();
entity.IndexDate = model.IndexDate;
entity.ProductId = model.ProductId;
entity.PartNumber = model.PartNumber;
entity.Name = model.Name;
entity.MetaKeywords = model.MetaKeywords ?? string.Empty;
entity.MetaDescription = model.MetaDescription ?? string.Empty;
entity.MetaTitle = model.MetaTitle ?? string.Empty;
entity.LimitedToStores = model.LimitedToStores;
entity.AvailableStores = !string.IsNullOrEmpty(model.AvailableStores) ? model.AvailableStores.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() :null;
entity.ShortDescription = model.ShortDescription ?? string.Empty;
entity.FullDescription = model.FullDescription ?? string.Empty;
entity.SeName = model.SeName ?? string.Empty;
entity.StockAvailability = model.StockAvailability;
entity.DeliveryDateId = model.DeliveryDateId;
entity.DeliveryDateName = model.DeliveryDateName ?? string.Empty;
entity.CategoryName = model.CategoryName ?? string.Empty;
entity.CategoryId = model.CategoryId;
entity.CategoryIdsLimitToStore = !string.IsNullOrEmpty(model.CategoryIdsLimitToStore) ? model.CategoryIdsLimitToStore.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() : null;
entity.CategoryParentNamesStr = model.CategoryParentNamesStr ?? string.Empty;
entity.CategoryIds =!string.IsNullOrEmpty(model.CategoryIdsStr) ? model.CategoryIdsStr.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() : null;
entity.CategoryIdsStr = model.CategoryIdsStr ?? string.Empty;
entity.IsPublishedCategory = model.IsPublishedCategory;
entity.ManufacturerNumber = model.ManufacturerNumber ?? string.Empty;
entity.ManufacturerName = model.ManufacturerName ?? string.Empty;
entity.ManufacturerId = model.ManufacturerId;
entity.ManufacturerLimitToStore = model.ManufacturerLimitToStore;
entity.IsPublishedManufacturer = model.IsPublishedManufacturer;
entity.Price = model.Price;
entity.VendorName = model.VendorName ?? string.Empty;
entity.VendorSeName = model.VendorSeName ?? string.Empty;
entity.ProductPictureUrl = model.HasImage ? (imageUrlPrefix + model.ProductPictureUrl) : string.Empty;
entity.HasImage = model.HasImage;
if (!string.IsNullOrEmpty(model.AssociatedProducts))
{
entity.AssociatedProductIds = model.AssociatedProducts.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList();
entity.AssociatedProducts = await GetAssociatedProducts(entity.AssociatedProductIds, jmContext, dataProvider, imageUrlPrefix);
}
return entity;
}
private static async Task<IList<ElasticIndexAssociatedProduct>> GetAssociatedProducts(List<int> associatedProductIds, JM_Core_ObjectContext jmContext, IDataProvider dataProvider, string imageUrlPrefix)
{
var pProductIds = dataProvider.GetStringParameter("ProductIds", string.Join(",", associatedProductIds));
var associatedToIndex = await Task.WhenAll
(
jmContext.QueryFromSql<ElasticIndexAssociatedProductEntity>("Exec SP_GetAssociatedProductsForElastic", pProductIds).ToList()
.Select(x => x.ToAssociatedIndexModel(imageUrlPrefix)).ToList()
);
return associatedToIndex;
}
private static async Task<ElasticIndexAssociatedProduct> ToAssociatedIndexModel(this ElasticIndexAssociatedProductEntity model, string imageUrlPrefix)
{
return await Task.Run(() => new ElasticIndexAssociatedProduct
{
ProductId = model.ProductId,
PartNumber = model.PartNumber,
Name = model.Name ?? string.Empty,
MetaKeywords = model.MetaKeywords ?? string.Empty,
MetaDescription = model.MetaDescription ?? string.Empty,
MetaTitle = model.MetaTitle ?? string.Empty,
LimitedToStores = model.LimitedToStores,
AvailableStores = !string.IsNullOrEmpty(model.AvailableStores) ? model.AvailableStores.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() : null,
ShortDescription = model.ShortDescription ?? string.Empty,
FullDescription = model.FullDescription ?? string.Empty,
SeName = model.SeName ?? string.Empty,
StockAvailability = model.StockAvailability,
DeliveryDateId = model.DeliveryDateId,
DeliveryDateName = model.DeliveryDateName ?? string.Empty,
CategoryName = model.CategoryName ?? string.Empty,
CategoryId = model.CategoryId,
CategoryIdsLimitToStore = !string.IsNullOrEmpty(model.CategoryIdsLimitToStore) ? model.CategoryIdsLimitToStore.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() : null,
CategoryParentNamesStr = model.CategoryParentNamesStr ?? string.Empty,
CategoryIds = !string.IsNullOrEmpty(model.CategoryIdsStr) ? model.CategoryIdsStr.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i)).ToList() : null,
CategoryIdsStr = model.CategoryIdsStr ?? string.Empty,
IsPublishedCategory = model.IsPublishedCategory,
ManufacturerNumber = model.ManufacturerNumber ?? string.Empty,
ManufacturerName = model.ManufacturerName ?? string.Empty,
ManufacturerId = model.ManufacturerId,
ManufacturerLimitToStore = model.ManufacturerLimitToStore,
IsPublishedManufacturer = model.IsPublishedManufacturer,
Price = model.Price,
VendorName = model.VendorName ?? string.Empty,
ProductPictureUrl = model.HasImage ? (imageUrlPrefix + model.ProductPictureUrl) : string.Empty,
HasImage = model.HasImage,
Specification = model.Specification ?? string.Empty
}); ;;
}
}
Это метод загрузки.
public IList<ElasticIndexGroupProduct> IndexGroupProducts(int[] groupProductIds)
{
try
{
if (groupProductIds == null)
return null;
var indexName = string.Format(_config.ElasticIndexName, _config.HostingEnvironment);
var indexingGroupProductQueue = _searchEngineData.GetElasticGroupProducts(groupProductIds).GetAwaiter().GetResult().ToList();
// Delete existing records
_client.DeleteByQuery<ElasticIndexGroupProduct>(d => d.Index(indexName).Query(q => q.Bool(bq => bq.Filter(fq => fq.Terms(t => t.Field(f => f.ProductId).Terms(indexingGroupProductQueue.Select(x => x.ProductId).ToArray()))))));
// Add records
var runningUpsertProductCount = 0;
do
{
var productsSubset = indexingGroupProductQueue.Skip(runningUpsertProductCount).Take(1000);
runningUpsertProductCount += 1000;
var descriptor = new BulkDescriptor();
productsSubset.ForEach(doc =>
{
descriptor.Index(indexName).Update<ElasticIndexGroupProduct>(u => u.Id(doc.Id).Doc(doc).Upsert(doc));
});
var upsertRespose = _client.Bulk(descriptor);
if (upsertRespose.ApiCall.Success)
{
productsSubset.ForEach(proupProduct =>
{
_jmProductService.UpdateElasticSearchIndexingDate(proupProduct.ProductId);
proupProduct.AssociatedProducts.ForEach(simpleProduct =>
{
_jmProductService.UpdateElasticSearchIndexingDate(proupProduct.ProductId);
});
});
}
} while (runningUpsertProductCount < indexingGroupProductQueue.Count);
return indexingGroupProductQueue;
}
catch (Exception e)
{
_logger.Error($"Error - ElasticSearch Product Indexing", e);
throw;
}
}