package elasticsearch;
import com.yunrun.common.elasticsearch.BaseElasticsearchService;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import java.util.HashMap;
import java.util.Map;
/**
* @author yuhh
* @date 2020-03-16 13:40
**/
public class QueryBuilderTest {
BaseElasticsearchService baseElasticsearchService;
/**
* 查询所有文档
* @author yuhh
* @date 2020/3/16 13:52
*/
public void matchAllQuery(){
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值的文档
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "match": {
* "待查询的字段": "待查询的值,多个值用" "隔开",
* "operator": "or"
* }
* }
* }
* @author yuhh
* @date 2020/3/16 13:52
*/
public void matchQuery(){
QueryBuilder queryBuilder = QueryBuilders.matchQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值的文档
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "common": {
* "message": {
* "待查询的字段": "待查询的值,多个值用" "隔开",
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/16 13:52
*/
public void commonTermsQuery(){
QueryBuilder queryBuilder = QueryBuilders.commonTermsQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段列表的值的分词查询分词中包含给定的值的文档
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "multi_match": {
* "query": "待查询的字段,多个好像无法正确查询出结果",
* "fields": [待查询的字段array]
* }
* }
* }
* @author yuhh
* @date 2020/3/16 18:11
*/
public void multiMatchQuery(){
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("待查询的值", "待查询的字段array");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值的文档,匹配的字段分词所在位置必须和待查询的值的分词位置一致
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "match_phrase": {
* "待查询的字段": "待查询的值,多个值用" "隔开"
* }
* }
* }
* @author yuhh
* @date 2020/3/17 15:27
*/
public void matchPhraseQuery(){
QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值的文档,匹配的字段分词所在位置必须和待查询的值的分词位置一致,
* 并且会将待查询的值的最后一个词作为前缀去进行查询
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "match_phrase_prefix": {
* "待查询的字段": "待查询的值,多个值用" "隔开"
* }
* }
* }
* @author yuhh
* @date 2020/3/17 15:43
*/
public void matchPhrasePrefix(){
QueryBuilder queryBuilder = QueryBuilders.matchPhrasePrefixQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 对子查询的结果做去重合并,score沿用子查询score的最大值
* 待查询的字段类型为text会分词
* 待查询的值会分词
* es:
* GET index/_search
* {
* "query": {
* "dis_max": {
* "queries": [
* 查询条件array
* ]
* }
* }
* }
* @author yuhh
* @date 2020/3/17 15:52
*/
public void disMaxQuery(){
QueryBuilder queryBuilder = QueryBuilders.disMaxQuery()
.add(QueryBuilders.matchPhrasePrefixQuery("待查询的字段", "待查询的值"))
.add(QueryBuilders.matchPhraseQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的idArray查询文档
* es:
* GET index/_search
* {
* "query": {
* "ids": {"values": [idArray]}
* }
* }
* @author yuhh
* @date 2020/3/17 16:02
*/
public void idsQuery(){
QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("idArray");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值的文档
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/17 16:24
*/
public void termQuery(){
QueryBuilder queryBuilder = QueryBuilders.termQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值在纠正指定次数(默认是2)后的文档
* 待查询的字段不会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "fuzzy": {
* "待查询的字段": {
* "value": "待查询的值,会被纠正",
* "fuzziness": 纠正次数
*
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/17 16:34
*/
public void fuzzyQuery(){
QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含前缀为给定的值的文档
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "prefix": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/17 16:51
*/
public void prefixQuery(){
QueryBuilder queryBuilder = QueryBuilders.prefixQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中在指定范围内的文档
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "range": {
* "待查询的字段": {
* "gte": "下限",
* "lte": "上限"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/17 17:48
*/
public void rangeQuery(){
QueryBuilder queryBuilder = QueryBuilders.rangeQuery("待查询的字段").gte("下限").lte("上限");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含待查询的值(包含通配符,*:任意字符;?:任意一个字符)的文档
* 注意:尽量别用*或?开头
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "wildcard": {
* "待查询的字段": {
* "value": "待查询的值(包含通配符,*:任意字符;?:任意一个字符)"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/17 18:02
*/
public void wildcardQuery(){
QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中符合正则表达式的文档
* 注意:最好在使用正则前,加上匹配的前缀
* 待查询的字段类型为text会分词
* 待查询的正则表达式不会分词
* es:
* GET index/_search
* {
* "query": {
* "regexp": {
* "待查询的字段": "待查询的正则表达式"
* }
* }
* }
* @author yuhh
* @date 2020/3/18 10:48
*/
public void regexpQuery(){
QueryBuilder queryBuilder = QueryBuilders.regexpQuery("待查询的字段", "待查询的正则表达式");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中符合查询字符串的文档
* 待查询的字段类型为text会分词
* 查询字符串会分词
* es:
* GET index/_search
* {
* "query": {
* "query_string": {
* "fields": [待查询字段array], 或 "default_field": 待查询的字段,
* "query": "查询字符串(支持的通配符。支持通过AND OR NOT !进行布尔运算。+:代表必须含有 -:代表不能含有)"
* }
* }
* }
* @author yuhh
* @date 2020/3/18 11:04
*/
public void queryStringQuery(){
Map<String, Float> fields = new HashMap<>();
fields.put("待查询的字段q", QueryStringQueryBuilder.DEFAULT_BOOST);
fields.put("待查询的字段w", QueryStringQueryBuilder.DEFAULT_BOOST);
// QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("查询字符串").defaultField("待查询的字段");
QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("查询字符串").fields(fields);
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中符合查询字符串的文档
* 待查询的字段类型为text会分词
* 查询字符串会分词
* es:
* GET index/_search
* {
* "simple_query_string": {
* "query_string": {
* "fields": [待查询字段array], 或 "default_field": 待查询的字段,
* "query": "查询字符串(支持的通配符。不支持通过AND OR NOT !进行布尔运算。+:代表必须含有 -:代表不能含有)"
* }
* }
* }
* @author yuhh
* @date 2020/3/18 11:04
*/
public void simpleQueryStringQuery(){
Map<String, Float> fields = new HashMap<>();
fields.put("待查询的字段q", QueryStringQueryBuilder.DEFAULT_BOOST);
fields.put("待查询的字段w", QueryStringQueryBuilder.DEFAULT_BOOST);
// QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("查询字符串").simpleQueryStringQuery("待查询的字段");
QueryBuilder queryBuilder = QueryBuilders.simpleQueryStringQuery("查询字符串").fields(fields);
baseElasticsearchService.search(queryBuilder);
}
/**
* 返回positive query的查询结果,如果positive query的查询结果也满足negative query,则改变其_source的值
* es:
* GET index/_search
* {
* "query": {
* "boosting": {
* "positive": {
* 指定用于查询的 query,最后返回结果必须满足 positive 对应的条件
* },
* "negative": {
* 指定影响相关性算分的 query,
* 如果positive query查询出来的文档同时满足 negative query,
* 那么最终得分 = positive query 得分 * negative_boost
* },
* "negative_boost": 范围是 0 到 1.0
* }
* }
* }
* @author yuhh
* @date 2020/3/18 14:26
*/
public void boostingQuery(){
QueryBuilder positiveQuery = QueryBuilders.wildcardQuery("待查询的字段", "待查询的值");
QueryBuilder negativeQuery = QueryBuilders.wildcardQuery("待查询的字段", "待查询的值");
QueryBuilder queryBuilder = QueryBuilders.boostingQuery(positiveQuery, negativeQuery).negativeBoost(0.1f);
baseElasticsearchService.search(queryBuilder);
}
/**
* 返回满足bool下所有query的结果
* es:
* GET index/_search
* {
* "query": {
* "bool": {
* "should": [
* query array
* 返回的文档可能满足should子句的条件。
* 在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。
* minimum_should_match参数定义了至少满足几个子句。
* ],
* "must": [
* query array
* 返回的文档必须满足must子句的条件,并且参与计算分值
* ],
* "must_not": [
* query array
* 返回的文档必须不满足must_not定义的条件。
* ],
* "filter": {query 返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值}
* }
* }
* }
* @author yuhh
* @date 2020/3/18 15:14
*/
public void boolQuery(){
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"))
.must(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"))
.should(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"))
.mustNot(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"))
.filter(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 等同于 term query ,但与其他Span查询一起使用
* es:
* GET index/_search
* {
* "query": {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/18 15:33
*/
public void spanTermQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanTermQuery("待查询的字段", "待查询的值");
baseElasticsearchService.search(queryBuilder);
}
/**
* 查询出待查询的值在待查询的字段的值的分词中前end个位置的文档
* es:
* GET index/_search
* {
* "query": {
* "span_first": {
* "match": {
* "span_term": {
* "待查询的字段": "待查询的值"
* }
* },
* "end": 最大位置值
* }
* }
* }
* @author yuhh
* @date 2020/3/18 15:51
*/
public void spanFirstQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanFirstQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
3);
baseElasticsearchService.search(queryBuilder);
}
/**
* 几个span query匹配的值的跨度必须在0-slop范围内,匹配的值的顺序必须和span query顺序一样
* 注意:所有span query的待查询的字段必须为同一个,不然会报异常
* es:
* GET index/_search
* {
* "query": {
* "span_near": {
* "clauses": [
* span query array
* ],
* "slop": 最大的跨度,
* "in_order": false
* }
* }
* }
* @author yuhh
* @date 2020/3/18 16:15
*/
public void spanNearQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanNearQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
12).addClause(QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 把include query查询结果中符合exclude query的文档排除后返回结果
* 注意:include query和exclude query的待查询的字段必须为同一个,不然会报异常
* 注意:include query和exclude query的span query都为span_term好像不会被拦截
* es:
* GET index/_search
* {
* "query": {
* "span_not": {
* "include": {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* },
* "exclude": {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/18 16:28
*/
public void spanNotQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanNotQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 返回与任何span query匹配的文档
* 注意:所有span query的待查询的字段必须为同一个,不然会报异常
* es:
* GET index/_search
* {
* "query": {
* "span_or": {
* "clauses": [
* span query array
* ]
* }
* }
* }
* @author yuhh
* @date 2020/3/18 17:12
*/
public void spanOrQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanOrQuery(QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"))
.addClause(QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 查找符合big query条件且包含little query的文档
* 注意:所有span query的待查询的字段必须为同一个,不然会报异常
* es:
* GET index/_search
* {
* "query": {
* "span_within": {
* "little": {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* },
* "big": {
* "span_near": {
* "clauses": [
* {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* },
* {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* }
* ],
* "slop": 1,
* "in_order": false
* }
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/18 17:27
*/
public void spanWithinQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanWithinQuery(
QueryBuilders.spanNearQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
12).addClause(QueryBuilders.spanTermQuery("待查询的字段", "待查询的值")),
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 查找符合big query条件的文档,之后筛选出包含little query的文档
* 注意:所有span query的待查询的字段必须为同一个,不然会报异常
* es:
* GET index/_search
* {
* "query": {
* "span_containing": {
* "little": {
* "待查询的字段": {
* "message": {
* "value": "待查询的值"
* }
* }
* },
* "big": {
* "span_near": {
* "clauses": [
* {
* "待查询的字段": {
* "message": {
* "value": "待查询的值"
* }
* }
* },
* {
* "待查询的字段": {
* "message": {
* "value": "待查询的值"
* }
* }
* }
* ],
* "slop": 1,
* "in_order": false
* }
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/18 17:40
*/
public void spanContainingQuery(){
QueryBuilder queryBuilder = QueryBuilders.spanWithinQuery(
QueryBuilders.spanNearQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
12).addClause(QueryBuilders.spanTermQuery("待查询的字段", "待查询的值")),
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 查找满足条件的文档
* es:
* GET index/_search
* {
* "query": {
* "span_multi": {
* "match": {
* 可以是term, range, prefix, wildcard, regexp 或者 fuzzy 查询
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/18 17:54
*/
public void spanMultiTermQueryBuilder(){
QueryBuilder queryBuilder = QueryBuilders.spanMultiTermQueryBuilder(QueryBuilders.wildcardQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 具体不清楚是干嘛的,好像只能用于span query下,猜测是从已查询到的文档中过滤出符合该query的文档
* 注意:所有span query的待查询的字段必须为同一个,不然会报异常
* es:
* GET index/_search
* {
* "query": {
* "span_near": {
* "clauses": [
* {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* },
* {
* "field_masking_span": {
* "query": {
* "span_term": {
* "待查询的字段": {
* "value": "待查询的值"
* }
* }
* },
* "field": "待查询的字段"
* }
* }
* ],
* "slop": 12,
* "in_order": false
* }
* }
* }
* @author yuhh
* @date 2020/3/18 18:05
*/
public void fieldMaskingSpanQuery(){
QueryBuilder queryBuilder = QueryBuilders.fieldMaskingSpanQuery(
QueryBuilders.spanTermQuery("待查询的字段", "待查询的值"),
"待查询的字段");
baseElasticsearchService.search(queryBuilder);
}
/**
* 查询满足条件的文档并返回指定的_source
* es:
* GET index/_search
* {
* "query": {
* "constant_score": {
* "filter": {
* query
* },
* "boost": 1.2
* }
* }
* }
* @author yuhh
* @date 2020/3/18 18:19
*/
public void constantScoreQuery(){
QueryBuilder queryBuilder = QueryBuilders.constantScoreQuery(
QueryBuilders.termQuery("待查询的字段", "待查询的值")).boost(1.2f);
baseElasticsearchService.search(queryBuilder);
}
/**
* 查询满足条件的文档但不对_source进行计算
* es:
* GET index/_search
* {
* "query": {
* "function_score": {
* "query": {
* query
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/19 14:09
*/
public void functionScoreQueryNoFunction(){
QueryBuilder queryBuilder = QueryBuilders.functionScoreQuery(
QueryBuilders.termQuery("待查询的字段", "待查询的值"));
baseElasticsearchService.search(queryBuilder);
}
/**
* 查询满足条件的文档并对_source进行计算
* 这个太过复杂,详情请看https://www.jianshu.com/p/f164f127bf33
* @author yuhh
* @date 2020/3/19 15:02
*/
public void functionScoreQuery(){
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders =
new FunctionScoreQueryBuilder.FilterFunctionBuilder[2];
filterFunctionBuilders[0] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(
QueryBuilders.termQuery("待查询的字段", "待查询的值"),
ScoreFunctionBuilders.fieldValueFactorFunction("待查询的字段"));
filterFunctionBuilders[1] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(
ScoreFunctionBuilders.randomFunction().seed(1).setField("待查询的字段"));
QueryBuilder queryBuilder = QueryBuilders.functionScoreQuery(
QueryBuilders.termQuery("待查询的字段", "待查询的值"),filterFunctionBuilders);
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据待查询字段array查询包含待查询的值array的文档
* 相关参数解释地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html
* es7.6测试查不到数据,不知道是什么原因
* es:
* GET index/_search
* {
* "query": {
* "more_like_this": {
* "fields": [
* 待查询字段array,es7.6必须为非空,所用的springboot-data-elasticsearch不兼容es7.6
* ],
* "like": ["待查询的值array"],
* "min_term_freq": 1,
* "max_query_terms": 12
* }
* }
* }
* @author yuhh
* @date 2020/3/19 18:00
*/
public void moreLikeThisQuery(){
String[] likes = new String[1];
likes[0] = "待查询的值";
QueryBuilder queryBuilder = QueryBuilders.moreLikeThisQuery(likes);
baseElasticsearchService.search(queryBuilder);
}
/**
* 用于nested嵌套类型的查询
* nested嵌套类型详细说明请看:https://blog.csdn.net/laoyang360/article/details/82950393
* es:
* GET index/_search
* {
* "query": {
* "nested": {
* "path": "类型为nested的字段名",
* "query": {
* query,例:
* "match": {
* "类型为nested的字段名.类型为nested的字段里的字段名": "待查询的值"
* }
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/27 17:32
*/
public void nestedQuery(){
QueryBuilder query = QueryBuilders.matchQuery("类型为nested的字段名.类型为nested的字段里的字段名", "待查询的值");
QueryBuilder queryBuilder = QueryBuilders.nestedQuery("类型为nested的字段名", query, ScoreMode.None);
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含给定的值array的文档
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "terms": {
* "待查询的字段": [
* 待查询的值array
* ]
* }
* }
* }
* @author yuhh
* @date 2020/3/27 17:42
*/
public void termsQuery(){
String[] values = new String[2];
values[0] = "待查询的值1";
values[1] = "待查询的值2";
QueryBuilder queryBuilder = QueryBuilders.termsQuery("待查询的字段", values);
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据查询语句的base编码格式进行查询,例如:
* eyJ0ZXJtIiA6IHsgIuW+heafpeivoueahOWtl+autSI6ICLlvoXmn6Xor6LnmoTlgLwiIH19 对应 {"term" : { "待查询的字段": "待查询的值" }}
* es:
* GET index/_search
* {
* "query": {
* "wrapper": {
* "query": "base64编码格式的查询语句"
* }
* }
* }
* @author yuhh
* @date 2020/3/27 17:55
*/
public void wrapperQuery(){
QueryBuilder queryBuilder = QueryBuilders.wrapperQuery("eyJ0ZXJtIiA6IHsgIuW+heafpeivoueahOWtl+autSI6ICLlvoXmn6Xor6LnmoTlgLwiIH19");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据文档类型查询,在7.0中已经被弃用
* es:
* GET /_search
* {
* "query": {
* "type" : {
* "value" : "待查询类型"
* }
* }
* }
* @author yuhh
* @date 2020/3/27 18:01
*/
public void typeQuery(){
QueryBuilder queryBuilder = QueryBuilders.typeQuery("待查询类型");
baseElasticsearchService.search(queryBuilder);
}
/**
* 根据给定的字段的值的分词查询分词中包含指定索引下指定id的文档的指定字段的值
* 待查询的字段类型为text会分词
* 待查询的值不会分词
* es:
* GET index/_search
* {
* "query": {
* "terms": {
* "待查询的字段": {
* "index": "作为查询条件的索引",
* "id": "作为查询条件的文档的id",
* "path": "作为查询条件的字段"
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/30 10:48
*/
public void termsLookupQuery(){
TermsLookup termsLookup = new TermsLookup("作为查询条件的索引", "作为查询条件的文档类型", "作为查询条件的文档的id", "作为查询条件的字段");
QueryBuilder queryBuilder = QueryBuilders.termsLookupQuery("待查询的字段", termsLookup);
baseElasticsearchService.search(queryBuilder);
}
/**
*
* es:
* GET index/_search
* {
* "query": {
* "script": {
* "script": {
* 作为查询运行的脚本,具体使用方法见:
* https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-using.html
* 例子,查询指定字段的值大于指定值的数据:
* "source": "doc['自定字段'].value > params.param1",
* "lang": "painless",
* "params": {
* "param1": 2
* }
* }
* }
* }
* }
* @author yuhh
* @date 2020/3/30 11:22
*/
public void scriptQuery(){
Map<String, Object> params = new HashMap<>();
params.put("param1", 2);
Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"doc['自定字段'].value > params.param1", params);
QueryBuilder queryBuilder = QueryBuilders.scriptQuery(script);
baseElasticsearchService.search(queryBuilder);
}
/**
* 查询文档中包含待查询字段的数据
* es:
* GET index/_search
* {
* "query": {
* "exists": {
* "field": "待查询字段"
* }
* }
* }
* @author yuhh
* @date 2020/3/30 16:17
*/
public void existsQuery(){
QueryBuilder queryBuilder = QueryBuilders.existsQuery("待查询字段");
baseElasticsearchService.search(queryBuilder);
}
}
例子2、’参考搜房网代码
package com.imooc.service.search;
import java.io.IOException;
import java.util.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.lucene.util.QueryBuilder;
import org.elasticsearch.action.*;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeAction;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequestBuilder;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.threadpool.ThreadPool;
import org.modelmapper.ModelMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.primitives.Longs;
import com.imooc.base.HouseSort;
import com.imooc.base.RentValueBlock;
import com.imooc.entity.House;
import com.imooc.entity.HouseDetail;
import com.imooc.entity.HouseTag;
import com.imooc.entity.SupportAddress;
import com.imooc.repository.HouseDetailRepository;
import com.imooc.repository.HouseRepository;
import com.imooc.repository.HouseTagRepository;
import com.imooc.repository.SupportAddressRepository;
import com.imooc.service.ServiceMultiResult;
import com.imooc.service.ServiceResult;
import com.imooc.service.house.IAddressService;
import com.imooc.web.form.MapSearch;
import com.imooc.web.form.RentSearch;
/**
* Created by 瓦力.
*/
@Service
public class SearchServiceImpl implements ISearchService {
private static final Logger logger = LoggerFactory.getLogger(ISearchService.class);
private static final String INDEX_NAME = "xunwu";
private static final String INDEX_TYPE = "house";
private static final String INDEX_TOPIC = "house_build";
@Autowired
private HouseRepository houseRepository;
@Autowired
private HouseDetailRepository houseDetailRepository;
@Autowired
private HouseTagRepository tagRepository;
@Autowired
private SupportAddressRepository supportAddressRepository;
@Autowired
private IAddressService addressService;
@Autowired
private ModelMapper modelMapper;
@Autowired
private RestHighLevelClient esClient;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
@KafkaListener(topics = INDEX_TOPIC)
private void handleMessage(String content) {
System.out.println("收到了通知");
try {
HouseIndexMessage message = objectMapper.readValue(content, HouseIndexMessage.class);
switch (message.getOperation()) {
case HouseIndexMessage.INDEX:
this.createOrUpdateIndex(message);
break;
case HouseIndexMessage.REMOVE:
this.removeIndex(message);
break;
default:
logger.warn("Not support message content " + content);
break;
}
} catch (IOException e) {
logger.error("Cannot parse json for " + content, e);
}
}
private void createOrUpdateIndex(HouseIndexMessage message) {
Long houseId = message.getHouseId();
House house = houseRepository.findOne(houseId);
if (house == null) {
logger.error("Index house {} dose not exist!", houseId);
this.index(houseId, message.getRetry() + 1);
return;
}
HouseIndexTemplate indexTemplate = new HouseIndexTemplate();
modelMapper.map(house, indexTemplate);
HouseDetail detail = houseDetailRepository.findByHouseId(houseId);
if (detail == null) {
// TODO 异常情况
}
modelMapper.map(detail, indexTemplate);
SupportAddress city = supportAddressRepository.findByEnNameAndLevel(house.getCityEnName(), SupportAddress.Level.CITY.getValue());
SupportAddress region = supportAddressRepository.findByEnNameAndLevel(house.getRegionEnName(), SupportAddress.Level.REGION.getValue());
String address = city.getCnName() + region.getCnName() + house.getStreet() + house.getDistrict() + detail.getDetailAddress();
ServiceResult<BaiduMapLocation> location = addressService.getBaiduMapLocation(city.getCnName(), address);
if (!location.isSuccess()) {
this.index(message.getHouseId(), message.getRetry() + 1);
return;
}
indexTemplate.setLocation(location.getResult());
List<HouseTag> tags = tagRepository.findAllByHouseId(houseId);
if (tags != null && !tags.isEmpty()) {
List<String> tagStrings = new ArrayList<>();
tags.forEach(houseTag -> tagStrings.add(houseTag.getName()));
indexTemplate.setTags(tagStrings);
}
// 查询houseId是否存在
boolean success;
GetRequest getRequest = new GetRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(houseId));
try {
GetResponse getResponse = esClient.get(getRequest);
if (!getResponse.isExists()) {
success = create(indexTemplate);
} else {
success = update(String.valueOf(houseId), indexTemplate);
}
} catch (IOException e) {
success = false;
logger.error("get查询错误" + houseId, e);
}
ServiceResult serviceResult = addressService.lbsUpload(location.getResult(), house.getStreet() + house.getDistrict(),
city.getCnName() + region.getCnName() + house.getStreet() + house.getDistrict(),
message.getHouseId(), house.getPrice(), house.getArea());
if (!success || !serviceResult.isSuccess()) {
this.index(message.getHouseId(), message.getRetry() + 1);
} else {
logger.debug("Index success with house " + houseId);
}
}
private void removeIndex(HouseIndexMessage message) {
Long houseId = message.getHouseId();
DeleteRequest deleteRequest = new DeleteRequest(INDEX_NAME, INDEX_TYPE, String.valueOf(message.getHouseId()));
try {
DeleteResponse deleteResponse = this.esClient.delete(deleteRequest);
} catch (IOException e) {
logger.error("delete删除错误" + houseId, e);
}
ServiceResult serviceResult = addressService.removeLbs(houseId);
}
@Override
public void index(Long houseId) {
this.index(houseId, 0);
}
private void index(Long houseId, int retry) {
if (retry > HouseIndexMessage.MAX_RETRY) {
logger.error("Retry index times over 3 for house: " + houseId + " Please check it!");
return;
}
HouseIndexMessage message = new HouseIndexMessage(houseId, HouseIndexMessage.INDEX, retry);
try {
kafkaTemplate.send(INDEX_TOPIC, objectMapper.writeValueAsString(message));
} catch (Exception e) {
logger.error("发送消息失败" + message);
}
}
private boolean create(HouseIndexTemplate indexTemplate) {
if (!updateSuggest(indexTemplate)) {
return false;
}
try {
IndexRequest indexRequest = new IndexRequest(
INDEX_NAME,
INDEX_TYPE,
String.valueOf(indexTemplate.getHouseId()));
String jsonString = objectMapper.writeValueAsString(indexTemplate);
indexRequest.source(jsonString, XContentType.JSON);
IndexResponse response = null;
try {
response = this.esClient.index(indexRequest);
logger.debug("Create index with house: " + indexTemplate.getHouseId());
if (response.status() == RestStatus.CREATED) {
return true;
} else {
return false;
}
} catch (IOException e) {
logger.error("index文档错误" + indexTemplate.getHouseId(), e);
return false;
}
} catch (JsonProcessingException e) {
logger.error("Error to index house " + indexTemplate.getHouseId(), e);
return false;
}
}
private boolean update(String esId, HouseIndexTemplate indexTemplate) {
if (!updateSuggest(indexTemplate)) {
return false;
}
try {
UpdateRequest updateRequest = new UpdateRequest(INDEX_NAME, INDEX_TYPE, esId);
String jsonString = objectMapper.writeValueAsString(indexTemplate);
updateRequest.doc(jsonString, XContentType.JSON);
try {
UpdateResponse response = this.esClient.update(updateRequest);
logger.debug("Update index with house: " + indexTemplate.getHouseId());
if (response.status() == RestStatus.OK) {
return true;
} else {
return false;
}
} catch (IOException e) {
logger.error("update索引错误" + indexTemplate.getHouseId(), e);
return false;
}
} catch (JsonProcessingException e) {
logger.error("Error to index house " + indexTemplate.getHouseId(), e);
return false;
}
}
@Override
public void remove(Long houseId) {
this.remove(houseId, 0);
}
@Override
public ServiceMultiResult<Long> query(RentSearch rentSearch) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.filter(
QueryBuilders.termQuery(HouseIndexKey.CITY_EN_NAME, rentSearch.getCityEnName())
);
if (rentSearch.getRegionEnName() != null && !"*".equals(rentSearch.getRegionEnName())) {
boolQuery.filter(
QueryBuilders.termQuery(HouseIndexKey.REGION_EN_NAME, rentSearch.getRegionEnName())
);
}
RentValueBlock area = RentValueBlock.matchArea(rentSearch.getAreaBlock());
if (!RentValueBlock.ALL.equals(area)) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(HouseIndexKey.AREA);
if (area.getMax() > 0) {
rangeQueryBuilder.lte(area.getMax());
}
if (area.getMin() > 0) {
rangeQueryBuilder.gte(area.getMin());
}
boolQuery.filter(rangeQueryBuilder);
}
RentValueBlock price = RentValueBlock.matchPrice(rentSearch.getPriceBlock());
if (!RentValueBlock.ALL.equals(price)) {
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(HouseIndexKey.PRICE);
if (price.getMax() > 0) {
rangeQuery.lte(price.getMax());
}
if (price.getMin() > 0) {
rangeQuery.gte(price.getMin());
}
boolQuery.filter(rangeQuery);
}
if (rentSearch.getDirection() > 0) {
boolQuery.filter(
QueryBuilders.termQuery(HouseIndexKey.DIRECTION, rentSearch.getDirection())
);
}
if (rentSearch.getRentWay() > -1) {
boolQuery.filter(
QueryBuilders.termQuery(HouseIndexKey.RENT_WAY, rentSearch.getRentWay())
);
}
boolQuery.must(
QueryBuilders.multiMatchQuery(rentSearch.getKeywords(),
HouseIndexKey.TITLE,
HouseIndexKey.TRAFFIC,
HouseIndexKey.DISTRICT,
HouseIndexKey.ROUND_SERVICE,
HouseIndexKey.SUBWAY_LINE_NAME,
HouseIndexKey.SUBWAY_STATION_NAME
));
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQuery)
.sort(HouseSort.getSortKey(rentSearch.getOrderBy()), SortOrder.fromString(rentSearch.getOrderDirection()))
.from(rentSearch.getStart())
.size(rentSearch.getSize())
.fetchSource(HouseIndexKey.HOUSE_ID, null);
searchRequest.source(searchSourceBuilder);
logger.debug("搜索参数"+boolQuery.toString());
List<Long> houseIds = new ArrayList<>();
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
if (response.status() != RestStatus.OK) {
return new ServiceMultiResult<>(0, houseIds);
}
for (SearchHit hit : response.getHits()) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
houseIds.add(Longs.tryParse(String.valueOf(sourceAsMap.get(HouseIndexKey.HOUSE_ID))));
}
return new ServiceMultiResult<>(response.getHits().totalHits, houseIds);
} catch (IOException e) {
logger.error("search查询错误", e);
return new ServiceMultiResult<>(0, null);
}
}
@Override
public ServiceResult<List<String>> suggest(String prefix) {
CompletionSuggestionBuilder suggestion = SuggestBuilders.completionSuggestion("suggest").prefix(prefix).size(5);
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("autocomplete", suggestion);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.suggest(suggestBuilder);
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
searchRequest.source(searchSourceBuilder);
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
} catch (IOException e) {
logger.error("suggest错误", e);
}
Suggest suggest = response.getSuggest();
if (suggest == null) {
return ServiceResult.of(new ArrayList<>());
}
Suggest.Suggestion result = suggest.getSuggestion("autocomplete");
int maxSuggest = 0;
Set<String> suggestSet = new HashSet<>();
for (Object term : result.getEntries()) {
if (term instanceof CompletionSuggestion.Entry) {
CompletionSuggestion.Entry item = (CompletionSuggestion.Entry) term;
if (item.getOptions().isEmpty()) {
continue;
}
for (CompletionSuggestion.Entry.Option option : item.getOptions()) {
String tip = option.getText().string();
if (suggestSet.contains(tip)) {
continue;
}
suggestSet.add(tip);
maxSuggest++;
}
}
if (maxSuggest > 5) {
break;
}
}
List<String> suggests = Lists.newArrayList(suggestSet.toArray(new String[]{}));
return ServiceResult.of(suggests);
}
@Override
public ServiceResult<Long> aggregateDistrictHouse(String cityEnName, String regionEnName, String district) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.filter(QueryBuilders.termQuery(HouseIndexKey.CITY_EN_NAME, cityEnName))
.filter(QueryBuilders.termQuery(HouseIndexKey.REGION_EN_NAME, regionEnName))
.filter(QueryBuilders.termQuery(HouseIndexKey.DISTRICT, district));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQuery)
.aggregation(AggregationBuilders.terms(HouseIndexKey.AGG_DISTRICT).field(HouseIndexKey.DISTRICT))
.size(0);
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
searchRequest.source(searchSourceBuilder);
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
if (response.status() == RestStatus.OK) {
Terms terms = response.getAggregations().get(HouseIndexKey.AGG_DISTRICT);
if (terms.getBuckets() != null && !terms.getBuckets().isEmpty()) {
return ServiceResult.of(terms.getBucketByKey(district).getDocCount());
}
} else {
logger.warn("Failed to Aggregate for " + HouseIndexKey.AGG_DISTRICT);
}
} catch (IOException e) {
logger.error("聚合错误", e);
}
return ServiceResult.of(0L);
}
@Override
public ServiceMultiResult<HouseBucketDTO> mapAggregate(String cityEnName) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.filter(QueryBuilders.termQuery(HouseIndexKey.CITY_EN_NAME, cityEnName));
AggregationBuilder aggBuilder = AggregationBuilders.terms(HouseIndexKey.AGG_REGION)
.field(HouseIndexKey.REGION_EN_NAME);
SearchSourceBuilder searchRequestBuilder = new SearchSourceBuilder();
searchRequestBuilder.query(boolQuery)
.aggregation(aggBuilder);
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
searchRequest.source(SearchSourceBuilder.searchSource());
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
List<HouseBucketDTO> buckets = new ArrayList<>();
if (response.status() != RestStatus.OK) {
return new ServiceMultiResult<>(0, buckets);
}
Terms terms = response.getAggregations().get(HouseIndexKey.AGG_REGION);
for (Terms.Bucket bucket : terms.getBuckets()) {
buckets.add(new HouseBucketDTO(bucket.getKeyAsString(), bucket.getDocCount()));
}
return new ServiceMultiResult<>(response.getHits().getTotalHits(), buckets);
} catch (IOException e) {
e.printStackTrace();
}
return new ServiceMultiResult<>(0, null);
}
@Override
public ServiceMultiResult<Long> mapQuery(String cityEnName, String orderBy,
String orderDirection,
int start,
int size) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.filter(QueryBuilders.termQuery(HouseIndexKey.CITY_EN_NAME, cityEnName));
SearchSourceBuilder searchRequestBuilder = new SearchSourceBuilder();
searchRequestBuilder.query(boolQuery)
.sort(HouseSort.getSortKey(orderBy), SortOrder.fromString(orderDirection))
.from(start)
.size(size);
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
searchRequest.source(SearchSourceBuilder.searchSource());
List<Long> houseIds = new ArrayList<>();
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
if (response.status() != RestStatus.OK) {
logger.warn("Search status is not ok for " + searchRequestBuilder);
return new ServiceMultiResult<>(0, houseIds);
}
for (SearchHit hit : response.getHits()) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
houseIds.add(Longs.tryParse(String.valueOf(sourceAsMap.get(HouseIndexKey.HOUSE_ID))));
}
return new ServiceMultiResult<>(response.getHits().getTotalHits(), houseIds);
} catch (IOException e) {
e.printStackTrace();
}
return new ServiceMultiResult<>(0, null);
}
@Override
public ServiceMultiResult<Long> mapQuery(MapSearch mapSearch) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.filter(QueryBuilders.termQuery(HouseIndexKey.CITY_EN_NAME, mapSearch.getCityEnName()));
boolQuery.filter(
QueryBuilders.geoBoundingBoxQuery("location")
.setCorners(
new GeoPoint(mapSearch.getLeftLatitude(), mapSearch.getLeftLongitude()),
new GeoPoint(mapSearch.getRightLatitude(), mapSearch.getRightLongitude())
));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQuery)
.sort(HouseSort.getSortKey(mapSearch.getOrderBy()),
SortOrder.fromString(mapSearch.getOrderDirection()))
.from(mapSearch.getStart())
.size(mapSearch.getSize());
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
searchRequest.types(INDEX_TYPE);
searchRequest.source(searchSourceBuilder);
List<Long> houseIds = new ArrayList<>();
SearchResponse response = null;
try {
response = this.esClient.search(searchRequest);
if (RestStatus.OK != response.status()) {
return new ServiceMultiResult<>(0, houseIds);
}
for (SearchHit hit : response.getHits()) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
houseIds.add(Longs.tryParse(String.valueOf(sourceAsMap.get(HouseIndexKey.HOUSE_ID))));
}
return new ServiceMultiResult<>(response.getHits().getTotalHits(), houseIds);
} catch (IOException e) {
logger.error("search查询错误", e);
return new ServiceMultiResult<>(0, null);
}
}
private boolean updateSuggest(HouseIndexTemplate indexTemplate) { // 使用了最普通的请求风格
try {
Map<String, String> params = Collections.emptyMap();
Map<String, Object> map = new HashMap<>();
map.put("text", Lists.newArrayList(indexTemplate.getTitle(),
indexTemplate.getLayoutDesc(), indexTemplate.getRoundService(),
indexTemplate.getDescription(), indexTemplate.getSubwayLineName(),
indexTemplate.getSubwayStationName()));
map.put("tokenizer", "ik_max_word");
String jsonString = null;
jsonString = objectMapper.writeValueAsString(map);
HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
Response response = this.esClient.getLowLevelClient().performRequest("GET", "xunwu/_analyze", params, entity);
String responseBody = EntityUtils.toString(response.getEntity());
Map<String, Object> responseMap = objectMapper.readValue(responseBody, HashMap.class);
List<HouseSuggest> suggests = new ArrayList<>();
List<Map<String, String>> tokens = (List<Map<String, String>>) responseMap.get("tokens");
for (Map<String, String> token : tokens) {
// 排序数字类型 & 小于2个字符的分词结果
if ("<NUM>".equals(token.get("type")) || token.get("token").length() < 2) {
continue;
}
HouseSuggest suggest = new HouseSuggest();
suggest.setInput(token.get("token"));
suggests.add(suggest);
}
// 定制化小区自动补全
HouseSuggest suggest = new HouseSuggest();
suggest.setInput(indexTemplate.getDistrict());
suggests.add(suggest);
indexTemplate.setSuggest(suggests);
return true;
} catch (Exception e) {
logger.error("错误", e);
return false;
}
}
private void remove(Long houseId, int retry) {
if (retry > HouseIndexMessage.MAX_RETRY) {
logger.error("Retry remove times over 3 for house: " + houseId + " Please check it!");
return;
}
HouseIndexMessage message = new HouseIndexMessage(houseId, HouseIndexMessage.REMOVE, retry);
try {
this.kafkaTemplate.send(INDEX_TOPIC, objectMapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
logger.error("Cannot encode json for " + message, e);
}
}
}