我尝试对包含自定义脚本函数的 ElasticSearch (6.4.0) API 执行搜索请求。在这个函数中,我尝试访问一个数组,它应该是响应数据的一部分。但我总是得到一个“null_pointer_exception”:
{
"error": {
"root_cause": [
{
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"i = 0; i < params['_source']['userStats'].length; i++) { } ",
" ^---- HERE"
],
"script": "double scoreBoost = 1; for (int i = 0; i < params['_source']['userStats'].length; i++) { } return _score * Math.log1p(scoreBoost);",
"lang": "painless"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "search--project",
"node": "...",
"reason": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"i = 0; i < params['_source']['userStats'].length; i++) { } ",
" ^---- HERE"
],
"script": "double scoreBoost = 1; for (int i = 0; i < params['_source']['userStats'].length; i++) { } return _score * Math.log1p(scoreBoost);",
"lang": "painless",
"caused_by": {
"type": "null_pointer_exception",
"reason": null
}
}
}
]
},
"status": 500
doc['userStats'] 也不起作用。
完整的请求正文如下:
{
"size": 10,
"query": {
"function_score": {
"query": {
"bool": {
"filter": {
"term": {
"_routing": "00000000-0000-0000-0000-000000000000"
}
},
"should": {
"query_string": {
"query": "123*",
"default_operator": "and",
"fuzziness": 1,
"analyze_wildcard": true,
"fields": [
"name^4",
"number^2",
"description",
"projectTypeId",
"projectStatusId",
"tags^1.5",
"company.name^2",
"company.number^2",
"company.industry",
"company.tags^1.5",
"company.companyTypes.name",
"company.companyContactInfos.value",
"company.companyContactInfos.addressLine1^1.25",
"company.companyContactInfos.addressLine2",
"company.companyContactInfos.zipCode^0.5",
"company.companyContactInfos.city",
"company.companyContactInfos.state",
"company.companyContactInfos.country",
"projectType.id",
"projectType.name",
"projectType.description",
"projectStatus.id",
"projectStatus.name",
"members.name",
"members.projectRoleName"
]
}
},
"minimum_should_match": 1
}
},
"functions": [
{
"script_score": {
"script": {
"source": "double scoreBoost = 1; for (int i = 0; i < params['_source']['userStats'].length; i++) { } return _score * Math.log1p(scoreBoost);",
"lang": "painless",
"params": {
"dtNow": 1543589276,
"uId": "00000000-0000-0000-0000-000000000000"
}
}
}
}
],
"score_mode": "multiply"
}
}
没有 script_score 部分,响应如下所示:
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 4,
"hits": [
{
"_index": "search--project",
"_type": "projectentity",
"_id": "00000000-0000-0000-0000-000000000000",
"_score": 4,
"_routing": "00000000-0000-0000-0000-000000000000",
"_source": {
"name": "123",
"description": "123...",
"projectTypeId": "00000000-0000-0000-0000-000000000000",
"projectStatusId": "00000000-0000-0000-0000-000000000000",
"tags": [
"232",
"2331",
"343"
],
"plannedDuration": 0,
"startDate": "2018-07-09T22:00:00Z",
"projectType": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "test 1",
"icon": "poll"
},
"projectStatus": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "In Progress",
"type": "progress"
},
"members": [
{
"userId": "00000000-0000-0000-0000-000000000000",
"name": "dummy",
"projectRoleName": "test",
"hasImage": false
},
{
"userId": "00000000-0000-0000-0000-000000000000",
"name": "dummy ",
"projectRoleName": "Manager",
"hasImage": false
}
],
"id": "00000000-0000-0000-0000-000000000000",
"userStats": [
{
"userId": "00000000-0000-0000-0000-000000000000",
"openCount": 55,
"lastOpened": 1543851773
},
{
"userId": "00000000-0000-0000-0000-000000000000",
"openCount": 9,
"lastOpened": 1542372179
}
],
"indexTime": "2018-12-03T15:42:53.157649Z"
}
}
]
}
映射看起来像这样:
{
"search--project": {
"aliases": {},
"mappings": {
"projectentity": {
"_routing": {
"required": true
},
"properties": {
"company": {
"properties": {
"companyTypes": {
"properties": {
"icon": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"indexTime": {
"type": "date"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"indexTime": {
"type": "date"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"number": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"members": {
"properties": {
"hasImage": {
"type": "boolean"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"projectRoleName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"userId": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
...
"plannedDuration": {
"type": "long"
},
"startDate": {
"type": "date"
},
"userStats": {
"properties": {
"lastOpened": {
"type": "long"
},
"openCount": {
"type": "long"
},
"userId": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
},
"settings": {
"index": {
"creation_date": "1539619646426",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "G5ohN1FvQBGkYFh_803Ifw",
"version": {
"created": "6040299"
},
"provided_name": "search--project"
}
}
}
有人对我做错了什么提出建议吗? 谢谢。
最佳答案
在查询中,您将params
标识为dtdNow
和uid
。因此,如果您想在脚本中使用它们,您可以执行 params.dtdNow
。
如果您想使用 _source
中的属性(即 userStats
),您应该使用 ctx._source.userStats.length
。文档中有更多示例:https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-examples.html .
编辑
对于 function_score 查询,您将使用 doc
映射或 params['_source']
。不同之处在于,当您使用 doc
时,它会缓存在内存中,并且 params['_source']
每次都会加载(请参阅 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-script-fields.html )。另一个警告是,如果启用了 fielddata
,则您需要使用未分析的字段或已分析的 text
字段。 https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-scripting-fields.html#modules-scripting-doc-vals
要实现您正在尝试做的事情,您应该能够在 userStats
对象中使用一个未分析的字段。像这样的 doc['userStats.openCount'].length
(这里我假设 openCount
是你的 userStats
对象所必需的)。
关于ElasticSearch 无痛,我如何访问 _source 中的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53598625/