springboot~elasticsearch對nested集(ji)合類型的(de)字段(duan)進(jin)行不等于的(de)檢索
對于es的數據類型來說,如果它是一個復雜類型,而我們需要把復雜類型進行檢索,那么應該定義成nested類型,而對于它(ta)的(de)檢索,如果是非集(ji)(ji)合(he)數(shu)據,它(ta)與其它(ta)類型沒有分別;而如果你的(de)nested存(cun)儲的(de)數(shu)據是一(yi)個集(ji)(ji)合(he),那在(zai)進行(xing)不等于這種操作時,就(jiu)需要說(shuo)明一(yi)下了。
舉例子
"id": "1",
"operate": [
{
"actionTime": "2017-03-21 11:57:37.700",
"operateType": "WangLu",
"wordNum": "3188",
"userName": "zidongluru"
},
{
"actionTime": "2017-03-21 11:57:37.700",
"operateType": "DaoRu",
"wordNum": "3188",
"userName": "qinbixue1609"
}
]
對于上面的數據,其中operate是一個nested類型的,它存儲數據為一個集合,我們查詢operateType不等于WangLu的數據,如果直接使用not_must配合term,那結果是不對的,它會把這個文檔正常返回,為什么?按說這個operate里是包含了WangLu的,如果包含它是不應該返回的;這就是es檢索nested集合處理不等于的問題,當會查詢所有集合中的元素,有一個不等于WangLu的(de)(de),它就認為是不等于的(de)(de),這與我(wo)們(men)的(de)(de)需求不符合,所以要想(xiang)其(qi)它方法。
script腳本檢索nested集合失敗
{
"size": 5,
"_source": [
"Gid",
"Type",
"operate"
],
"query": {
"bool": {
"must": [
{
"nested": {
"path": "operate",
"query": {
"script": {
"script": "doc['operate.operateType'].stream().map(o->o).filter(o->o=='YiJiaoSu').count()==0"
}
}
}
},
{
"term": {
"Gid": "1970325267114815"
}
}
]
}
}
}
使用function方式解決了這個問題
- 參考
{
"size": 5,
"_source": [
"Gid",
"Type",
"operate"
],
"query": {
"bool": {
"must": [
{
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"script_score": {
"script": {
"source": "params._source.operate.stream().map(o->o.operateType).filter(o->o=='YiJiaoSu').count()==0 ? 1 : 0"
}
}
}
],
"min_score": 1
}
},
{
"term": {
"Id": "1970325267114815"
}
}
]
}
}
}
這種由于是集合里(li)的集合再檢索,所(suo)以需要(yao)和(he)其它檢索條(tiao)件一起用(yong),全表(biao)檢索,性能比(bi)較差。
翻譯成java客戶端代碼
String val = "條件";
String name = "nested內部字段名";
String scoreStr = "params._source.operate==null || params._source.operate.stream().map(o->o." + name + ").filter(o->o=='" + val + "').count()==0? 1 : 0";
Script sc = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scoreStr, MapUtil.empty());
ScriptScoreFunctionBuilder builder = new ScriptScoreFunctionBuilder(sc);
FunctionScoreQueryBuilder scoreBuilder = QueryBuilders.functionScoreQuery(builder);
scoreBuilder.setMinScore(1);
scoreBuilder.scoreMode(FunctionScoreQuery.ScoreMode.FIRST);
queryIncludeBuilder.must(scoreBuilder);