通过elasticsearch进行筛选高级查询

    技术2022-07-15  56

    项目要求:客户可以筛选不同的index 并且可以进行多条条件的筛选。

    刚开始,一开始对于需求不够明确,认为搜索条件中的 第四个条件 “或or且”是针对于当前条件单独的描述。例如,名字等于xxx (且) 且表示当前条件必须成立。但是这样的理解是不正确的。 正确的查询:且表示上下俩条数据都必须存在,或表示当前条件可以存在可以不存在。 而后,被公司的大哥指点了一番,通过大集合小集合先对条件进行了处理,然后进行查询,完成的高级查询。

    解决思路:首先以“或”作为条件的分割, 如果在条件列表中,出现了或,则证明或后面的条件是单独的条件,例如:A and B or C 那么证明我们想要的查询其实为(A and B) or C 对条件列表进行遍历, 当列表的长度为1或者2的时候单独处理,当条件条数大于3的时候,首先判断当前条件中 是 或or且 如果是且,那么将且封装进入一个小的list 然后进行下一次遍历,如果当前条件中需求为或,那么证明之前的条件+当前条件为组合,所以将当前条件装入小list 然后将小list装入大list中,每次遇到或。都进行将数据加入小list ,然后将小list加入大list 然后给小list重新创建对象(一开始是调用了list.clear,但是这个方法会将内存中所有小list的引用都清除,但是我们是要保存大list中小list的数据的),这样循环下去,将不同的条件都封装在大list中,大list中包含多个小list 小list中包含多个条件,各个小list之间的关系是or 小list中各个条件之间的关系为and 对应到es的dsl语句为:

    POST mhdz,tlsmz,wbswxx,hotel/_search { "profile": "true", "query": { "bool": { "should": [ { "bool": { "must": [ { "multi_match": { "query": "李四", "fields": [ "xm", "xm.keyword" ], "boost": 0.5, "minimum_should_match": "75%" } }, { "match": { "zjhm": { "query": "3604251999061622", "boost": 3, "fuzziness": "AUTO" } } } ] } }, { "bool": { "must": [ { "multi_match": { "query": "张三", "fields": [ "xm", "xm.keyword" ], "boost": 0.5, "minimum_should_match": "75%" } }, { "match": { "zjhm": { "query": "3604251999061122", "boost": 3, "fuzziness": "AUTO" } } } ] } } ] } } } private SearchRequest getSynQueryResultByCondition(HashMap<String, Object> bindParams) { SearchRequest searchRequest; // 获取查询的索引列表 String[] indexNames = (String[]) bindParams.get("indexKeys"); // 获取查询的条件列表 List<HashMap<String, String>> options = (List<HashMap<String, String>>) bindParams.get("conditions"); // 1.构建查询请求 if (indexNames != null && indexNames.length > 0) { searchRequest = new SearchRequest(indexNames); } else { // 所有的名称 EsIndex esIndex = new EsIndex(); esIndex.setDelFlag(false); String[] indexArray = esIndexService.select(esIndex).stream().map(EsIndex::getIndexKey).toArray(String[]::new); searchRequest = new SearchRequest(indexArray); } // 4.构建最外面的boolQuery BoolQueryBuilder query = QueryBuilders.boolQuery(); if (options != null && options.size() > 0) { // 大list ArrayList<List<HashMap<String, String>>> orList = Lists.newArrayList(); // 小list ArrayList<HashMap<String, String>> andList = Lists.newArrayList(); for (int i = 0; i < options.size(); i++) { // 如果只有一条数据,直接装入orList if (options.size() == 1) { andList.add(options.get(i)); orList.add(andList); break; } String searchRelation = options.get(i).get("searchRelation"); // 如果有俩条数据,判断他们的关系 if (options.size() == 2) { if (Integer.toString(SearchRelationEnum.Q.getKey()).equals(searchRelation)) { orList.add(options); } else { andList.add(options.get(0)); orList.add(andList); andList = new ArrayList<>(); andList.add(options.get(1)); orList.add(andList); } break; } // 三条以上 判断倒数第二条是且还是或,最后一条不考虑且或 if (i == options.size() - 2) { if (Integer.toString(SearchRelationEnum.Q.getKey()).equals(searchRelation)) { andList.add(options.get(i)); andList.add(options.get(i + 1)); orList.add(andList); } else { andList.add(options.get(i)); orList.add(andList); andList = new ArrayList<>(); andList.add(options.get(i + 1)); orList.add(andList); } break; } // 如果是且 装入小list if (Integer.toString(SearchRelationEnum.Q.getKey()).equals(searchRelation)) { andList.add(options.get(i)); } else { // 如果是或 先装入小的,然后装入大的,然后清空小的 andList.add(options.get(i)); orList.add(andList); andList = new ArrayList<>(); } } orList.forEach(or -> { BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); for (HashMap<String, String> stringHashMap : or) { // 获取搜索前提条件 String searchPremise = stringHashMap.get("searchPremise"); // 获取搜索符号 String searchSymbol = stringHashMap.get("searchSymbol"); // 获取搜索内容 String searchContent = stringHashMap.get("searchContent"); // 索取搜索关系 String analyzeType = stringHashMap.get("analyzeType"); //判断analyzeType 是否等于 0 如果等于0 则证明他是keyword 字段,不需要分词, if ("0".equals(analyzeType)){ // 判断searchSymbol是等于还是包含。如果是等于 设置他的前提条件为searchSymbol analyzeType = "whitespace"; }else { if (Integer.toString(SearchSymbolEnum.DY.getKey()).equals(searchSymbol)){ analyzeType = "whitespace"; searchPremise = searchPremise + ".keyword"; } } // 查询query 姓名 等于 或 // 判断前提条件是否为姓名 if ("xm".equals(searchPremise)) { QueryBuilder multiQuery; // 判断搜索符号是等于还是包含 // 如果是等于 if (Integer.toString(SearchSymbolEnum.DY.getKey()).equals(searchSymbol)) { // 对于xm字段,xm的keyword字段 进行多字段查询,当条件为必须等于的时候,将查询条件不分词完成必须完全匹配 multiQuery = QueryBuilders.multiMatchQuery(searchContent, "xm", "xm.keyword").analyzer(analyzeType).boost((float) 0.5); boolQuery.must(multiQuery); } else if (Integer.toString(SearchSymbolEnum.BH.getKey()).equals(searchSymbol)) { // 包含关系中 姓名必须匹配75%以上,才会返回 multiQuery = QueryBuilders.multiMatchQuery(searchContent, "xm", "xm.keyword").minimumShouldMatch("75%").boost((float) 0.5); // 如果是且 boolQuery.must(multiQuery); } } else if ("lxdh".equals(searchPremise)) { // 手机号码查询设置查询时可以出错,可出错的个数由ES决定 QueryBuilder matchQuery = QueryBuilders.matchQuery("lxdh", searchContent).fuzziness("AUTO").boost(3); boolQuery.must(matchQuery); } else if ("zjhm".equals(searchPremise)) { QueryBuilder matchQuery = QueryBuilders.matchQuery("zjhm", searchContent).fuzziness("AUTO").boost(5); boolQuery.must(matchQuery); } else{ QueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(searchContent,searchPremise).analyzer(analyzeType); boolQuery.must(multiMatchQuery);} } query.should(boolQuery); }); } //6.高亮 HighlightBuilder highlightBuilder = new HighlightBuilder(); // 所有查询出来的字段全部高亮 HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("*").requireFieldMatch(false); highlightTitle.highlighterType("unified"); highlightBuilder.field(highlightTitle); // 3.构建高亮 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(query).highlighter(highlightBuilder); // 2.将查询构建器放入查询请求中 searchRequest.source(sourceBuilder); return searchRequest; }
    Processed: 0.011, SQL: 9