ElasticSearch - 使用 NEST 5.x 在嵌套列表 <T> 中添加元素
ElasticSearch - Add element inside nested List<T> using NEST 5.x
我的 ElasticSearch 索引中有一个列表。如何使用 NEST 2 将新元素添加到列表中?我已经搜索了我的问题的答案,但我找到的都是 ,但它对我不起作用。
型号:
public class TicketModel
{
public Guid Id { get; set; }
public Guid IdUser { get; set; }
public Guid IdAuthor { get; set; }
public Guid? IdAssignedUser { get; set; }
public Guid? IdAsset { get; set; }
public Guid? IdOwner { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ClosingDate { get; set; }
public DateTime? DueDate { get; set; }
public DateTime? LastDateUserView { get; set; }
public DateTime? LastDateAssignedUserView { get; set; }
public string TicketCode { get; set; }
public string Title { get; set; }
public int IdCategory { get; set; }
public int? IdSubcategory { get; set; }
public short? IdPriority { get; set; }
public short IdState { get; set; }
public bool IsNew { get; set; }
public List<TicketMessageModel> TicketMessageList { get; set; }
}
public class TicketMessageModel
{
public Guid Id { get; set; }
public Guid IdTicket { get; set; }
public Guid IdUserFrom { get; set; }
public Guid? IdUserTo { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? DeleteDate { get; set; }
public string Message { get; set; }
public bool HideToFinalUser { get; set; }
public byte? MessageType { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public Guid Id { get; set; }
public Guid? IdTicketMessage { get; set; }
public string FileName { get; set; }
public string FileTitle { get; set; }
public string FileOriginalName { get; set; }
public byte FileType { get; set; }
}
我尝试使用其他答案找到出路,但我被困在这里:
client.Update<ElasticSearchTickets.TicketMessageModel, object>(new DocumentPath<ElasticSearchTickets.TicketMessageModel>(elem.Id),
q => q.Script(x => x.Inline("ctx._source.MessageFileList += elem"))./*??*/);
提前致谢。
编辑:
这是我尝试在列表中插入新元素的代码:
ElasticSearchTickets.TicketMessageModel elem = new ElasticSearchTickets.TicketMessageModel()
{
CreationDate = message.CreationDate,
DeleteDate = message.DeleteDate,
HideToFinalUser = message.HideToFinalUser,
Id = message.Id,
IdTicket = message.IdTicket,
IdUserFrom = message.IdUserFrom,
IdUserTo = message.IdUserTo,
Message = message.Message,
MessageType = message.MessageType,
MessageFileList = tempList
};
var response = client.Update<ElasticSearchTickets.TicketModel, object>(new DocumentPath<ElasticSearchTickets.TicketModel>(elem.IdTicket.ToString()), q => q
.Script(s => s
.Inline("if (ctx._source.TicketMessageList == null) { ctx._source.TicketMessageList = element; } else { ctx._source.TicketMessageList += element; }")
.Params(d => d.Add("element", new [] { elem }))
));
但是现在我得到一个服务器错误,因为 属性 "element" 还没有声明。如何解决这个问题?
这是映射:
"mappings": {
"ticket": {
"properties": {
"ClosingDate": {
"type": "date"
},
"CreationDate": {
"type": "date"
},
"DueDate": {
"type": "date"
},
"Id": {
"type": "keyword"
},
"IdAsset": {
"type": "keyword"
},
"IdAssignedUser": {
"type": "keyword"
},
"IdAuthor": {
"type": "keyword"
},
"IdCategory": {
"type": "integer"
},
"IdOwner": {
"type": "keyword"
},
"IdPriority": {
"type": "short"
},
"IdState": {
"type": "short"
},
"IdSubcategory": {
"type": "integer"
},
"IdUser": {
"type": "keyword"
},
"IsNew": {
"type": "boolean"
},
"LastDateAssignedUserView": {
"type": "date"
},
"LastDateUserView": {
"type": "date"
},
"TicketCode": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"TicketMessageList": {
"type": "nested",
"properties": {
"CreationDate": {
"type": "date"
},
"DeleteDate": {
"type": "date"
},
"HideToFinalUser": {
"type": "boolean"
},
"Id": {
"type": "keyword"
},
"IdTicket": {
"type": "keyword"
},
"IdUserFrom": {
"type": "keyword"
},
"IdUserTo": {
"type": "keyword"
},
"Message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"MessageFileList": {
"properties": {
"FileName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileOriginalName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileTitle": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileType": {
"type": "short"
},
"Id": {
"type": "keyword"
},
"IdTicketMessage": {
"type": "keyword"
}
}
},
"MessageType": {
"type": "short"
}
}
},
"Title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
这是一个精简的例子
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(connectionSettings);
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
client.CreateIndex(defaultIndex, c => c
.Mappings(ms => ms
.Map<TicketMessageModel>(m => m
.AutoMap()
.Properties(p => p
.Nested<TicketMessageFilesModel>(n => n
.Name(nn => nn.MessageFileList)
.AutoMap()
)
)
)
)
);
var id = "ticketmessage";
client.Index(new TicketMessageModel
{
Id = id,
MessageFileList = new List<UserQuery.TicketMessageFilesModel>
{
new TicketMessageFilesModel { Id = "file1" }
}
});
client.Update<TicketMessageModel, object>(id, q => q
.Script("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = elem; } else { ctx._source.messageFileList += elem; }")
.Params(d => d
.Add("elem", new[] { new TicketMessageFilesModel { Id = "file2" } })
)
);
var getResponse = client.Get<TicketMessageModel>(id);
}
public class TicketMessageModel
{
public string Id { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public string Id { get; set; }
}
getResponse
JSON 响应是
{
"_index" : "default-index",
"_type" : "ticketmessagemodel",
"_id" : "ticketmessage",
"_version" : 2,
"found" : true,
"_source" : {
"id" : "ticketmessage",
"messageFileList" : [ {
"id" : "file1"
}, {
"id" : "file2"
} ]
}
}
一些兴趣点:
- 您需要通过检查它是否为空来处理列表中可能没有任何项目的情况
- 为了追加到列表中,您需要将要追加的项目包装在一个数组中,这样列表和数组就可以追加在一起。
- 您需要使用
_source
中存在的序列化字段名称。默认情况下,在 Elasticsearch 中序列化为字段名称时,NEST camel 会使用 POCO 属性 名称
编辑:
看起来您正在使用 NEST 5.x 对抗 Elasticsearch 5.x; 5.x 中的默认脚本语言是 Painless 而不是 2.x 中的 Groovy,因此必须对脚本进行一些细微的差别。
这是一个适用于 5.x 的无痛版本
client.Update<TicketMessageModel, object>(id, q => q
.Script(s => s
.Inline("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = new ArrayList(); } ctx._source.messageFileList.add(params.elem);")
.Params(d => d
.Add("elem", new TicketMessageFilesModel { Id = "file2" })
)
)
);
查看 guide on Painless 了解更多详情。您也可以将原始示例与 Groovy 一起使用,方法是在 .Script()
内指定 .Lang("groovy")
,但您还需要允许内联 Groovy 脚本到 运行添加
script.engine.groovy.inline: true
到Elasticsearch.yml配置。 Groovy scripts are disabled by default for security reasons.
我的 ElasticSearch 索引中有一个列表。如何使用 NEST 2 将新元素添加到列表中?我已经搜索了我的问题的答案,但我找到的都是
型号:
public class TicketModel
{
public Guid Id { get; set; }
public Guid IdUser { get; set; }
public Guid IdAuthor { get; set; }
public Guid? IdAssignedUser { get; set; }
public Guid? IdAsset { get; set; }
public Guid? IdOwner { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ClosingDate { get; set; }
public DateTime? DueDate { get; set; }
public DateTime? LastDateUserView { get; set; }
public DateTime? LastDateAssignedUserView { get; set; }
public string TicketCode { get; set; }
public string Title { get; set; }
public int IdCategory { get; set; }
public int? IdSubcategory { get; set; }
public short? IdPriority { get; set; }
public short IdState { get; set; }
public bool IsNew { get; set; }
public List<TicketMessageModel> TicketMessageList { get; set; }
}
public class TicketMessageModel
{
public Guid Id { get; set; }
public Guid IdTicket { get; set; }
public Guid IdUserFrom { get; set; }
public Guid? IdUserTo { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? DeleteDate { get; set; }
public string Message { get; set; }
public bool HideToFinalUser { get; set; }
public byte? MessageType { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public Guid Id { get; set; }
public Guid? IdTicketMessage { get; set; }
public string FileName { get; set; }
public string FileTitle { get; set; }
public string FileOriginalName { get; set; }
public byte FileType { get; set; }
}
我尝试使用其他答案找到出路,但我被困在这里:
client.Update<ElasticSearchTickets.TicketMessageModel, object>(new DocumentPath<ElasticSearchTickets.TicketMessageModel>(elem.Id),
q => q.Script(x => x.Inline("ctx._source.MessageFileList += elem"))./*??*/);
提前致谢。
编辑:
这是我尝试在列表中插入新元素的代码:
ElasticSearchTickets.TicketMessageModel elem = new ElasticSearchTickets.TicketMessageModel()
{
CreationDate = message.CreationDate,
DeleteDate = message.DeleteDate,
HideToFinalUser = message.HideToFinalUser,
Id = message.Id,
IdTicket = message.IdTicket,
IdUserFrom = message.IdUserFrom,
IdUserTo = message.IdUserTo,
Message = message.Message,
MessageType = message.MessageType,
MessageFileList = tempList
};
var response = client.Update<ElasticSearchTickets.TicketModel, object>(new DocumentPath<ElasticSearchTickets.TicketModel>(elem.IdTicket.ToString()), q => q
.Script(s => s
.Inline("if (ctx._source.TicketMessageList == null) { ctx._source.TicketMessageList = element; } else { ctx._source.TicketMessageList += element; }")
.Params(d => d.Add("element", new [] { elem }))
));
但是现在我得到一个服务器错误,因为 属性 "element" 还没有声明。如何解决这个问题?
这是映射:
"mappings": {
"ticket": {
"properties": {
"ClosingDate": {
"type": "date"
},
"CreationDate": {
"type": "date"
},
"DueDate": {
"type": "date"
},
"Id": {
"type": "keyword"
},
"IdAsset": {
"type": "keyword"
},
"IdAssignedUser": {
"type": "keyword"
},
"IdAuthor": {
"type": "keyword"
},
"IdCategory": {
"type": "integer"
},
"IdOwner": {
"type": "keyword"
},
"IdPriority": {
"type": "short"
},
"IdState": {
"type": "short"
},
"IdSubcategory": {
"type": "integer"
},
"IdUser": {
"type": "keyword"
},
"IsNew": {
"type": "boolean"
},
"LastDateAssignedUserView": {
"type": "date"
},
"LastDateUserView": {
"type": "date"
},
"TicketCode": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"TicketMessageList": {
"type": "nested",
"properties": {
"CreationDate": {
"type": "date"
},
"DeleteDate": {
"type": "date"
},
"HideToFinalUser": {
"type": "boolean"
},
"Id": {
"type": "keyword"
},
"IdTicket": {
"type": "keyword"
},
"IdUserFrom": {
"type": "keyword"
},
"IdUserTo": {
"type": "keyword"
},
"Message": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"MessageFileList": {
"properties": {
"FileName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileOriginalName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileTitle": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"FileType": {
"type": "short"
},
"Id": {
"type": "keyword"
},
"IdTicketMessage": {
"type": "keyword"
}
}
},
"MessageType": {
"type": "short"
}
}
},
"Title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
这是一个精简的例子
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(connectionSettings);
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
client.CreateIndex(defaultIndex, c => c
.Mappings(ms => ms
.Map<TicketMessageModel>(m => m
.AutoMap()
.Properties(p => p
.Nested<TicketMessageFilesModel>(n => n
.Name(nn => nn.MessageFileList)
.AutoMap()
)
)
)
)
);
var id = "ticketmessage";
client.Index(new TicketMessageModel
{
Id = id,
MessageFileList = new List<UserQuery.TicketMessageFilesModel>
{
new TicketMessageFilesModel { Id = "file1" }
}
});
client.Update<TicketMessageModel, object>(id, q => q
.Script("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = elem; } else { ctx._source.messageFileList += elem; }")
.Params(d => d
.Add("elem", new[] { new TicketMessageFilesModel { Id = "file2" } })
)
);
var getResponse = client.Get<TicketMessageModel>(id);
}
public class TicketMessageModel
{
public string Id { get; set; }
public List<TicketMessageFilesModel> MessageFileList { get; set; }
}
public class TicketMessageFilesModel
{
public string Id { get; set; }
}
getResponse
JSON 响应是
{
"_index" : "default-index",
"_type" : "ticketmessagemodel",
"_id" : "ticketmessage",
"_version" : 2,
"found" : true,
"_source" : {
"id" : "ticketmessage",
"messageFileList" : [ {
"id" : "file1"
}, {
"id" : "file2"
} ]
}
}
一些兴趣点:
- 您需要通过检查它是否为空来处理列表中可能没有任何项目的情况
- 为了追加到列表中,您需要将要追加的项目包装在一个数组中,这样列表和数组就可以追加在一起。
- 您需要使用
_source
中存在的序列化字段名称。默认情况下,在 Elasticsearch 中序列化为字段名称时,NEST camel 会使用 POCO 属性 名称
编辑:
看起来您正在使用 NEST 5.x 对抗 Elasticsearch 5.x; 5.x 中的默认脚本语言是 Painless 而不是 2.x 中的 Groovy,因此必须对脚本进行一些细微的差别。
这是一个适用于 5.x 的无痛版本
client.Update<TicketMessageModel, object>(id, q => q
.Script(s => s
.Inline("if (ctx._source.messageFileList == null) { ctx._source.messageFileList = new ArrayList(); } ctx._source.messageFileList.add(params.elem);")
.Params(d => d
.Add("elem", new TicketMessageFilesModel { Id = "file2" })
)
)
);
查看 guide on Painless 了解更多详情。您也可以将原始示例与 Groovy 一起使用,方法是在 .Script()
内指定 .Lang("groovy")
,但您还需要允许内联 Groovy 脚本到 运行添加
script.engine.groovy.inline: true
到Elasticsearch.yml配置。 Groovy scripts are disabled by default for security reasons.