本文共 6888 字,大约阅读时间需要 22 分钟。
我们都知道,Elasticsearch作为搜索引擎被广泛应用在各个领域,尤其是电子商务网站和App的检索,如下几乎囊括的商城大部分搜索使用场景查询定义,其中包括:
另外,针对Elasticsearch搜索场景,此处不选择官方提供的查询客户端(后期会@Deprecated),而是使用 作为ES检索查询客户端,可能很多伙计都知道OkHttp是一个高效的HTTP客户端,被业界广泛应用在Http请求场景,它有以下特性:
基础BaseQuery定义,以及其他枚举类型定义;
@Getterpublic abstract class BaseQueryimplements Serializable { private static final long serialVersionUID = -8937265256480681309L; /** * Field查询权重 */ private Float boost; public final Q boost(Float boost){ this.boost = boost; //noinspection unchecked return (Q)this; }} public static enum ZeroTerms { /** zero terms*/ NONE, ALL } public enum Operator { /**操作方向*/ OR, AND } public enum Order { /**排序方向*/ ASC, DESC }@Getter@Builderpublic class Sort implements Serializable { private static final long serialVersionUID = -5574272690024012413L; /** * 排序字段 */ private String field; /** * 排序指令 */ private Order order; /** * 脚本排序 */ private Script script; /** * 脚本排序Filed数据类型 */ private String type;}
/** 精确查询:文档主键Id列表查询 * @author
/** 存在查询 * @author
/* * 通配符模糊匹配查询 * @author
/** 范围查询 * @author
/** 精确匹配查询 * @author
* 多属多值精确匹配查询 * @author
/** 分词匹配查询 * 例如:“中国杭州”->分词为“中国”、"杭州" * @author
/** 分词匹配查询:多字段Match匹配查询 * @author
/** 嵌套(nested)查询 * @author
/* * script查询 * @author
评分为所有子查询评分之和;
/** 组合查询,组合第2部分定义各种组合 * @author
评分为与高权重子查询的打分高度相关;
@Data@Builder@EqualsAndHashCode(callSuper = true)public class DisMaxQuery extends BaseQuery{ private static final long serialVersionUID = -3096588829428648257L; /** * 平局参数:将其他field匹配查询语句的评分也考虑其中 */ private Float tieBreaker; /** * 文档必须匹配查询内容 */ public List must; /** * 文档必须不允许匹配查询内容 */ public List mustNot; /** * 文档过滤匹配内容,并不影响文档匹配得分 */ public List filter; /** * 文档匹配上可以增加相关得分,相当于or */ public List should; /** * 一个文档分词后匹配的百分比,例如:80%, */ private String minimumShouldMatch; public DisMaxQuery addMust(BaseQuery query) { if (must == null) { must = Lists.newArrayList(); } must.add(query); return this; } public DisMaxQuery addMustNot(BaseQuery query) { if (mustNot == null) { mustNot = Lists.newArrayList(); } mustNot.add(query); return this; } public DisMaxQuery addFilter(BaseQuery query) { if (filter == null) { filter = Lists.newArrayList(); } filter.add(query); return this; } private DisMaxQuery addShould(BaseQuery query) { if (should == null) { should = Lists.newArrayList(); } should.add(query); return this; }}
/** * 构建OkHttp客户端 */ private static AtomicReferenceINSTANCE = new AtomicReference<>(); public OkHttpClient getClient(){ for (; ;){ //Http连接对象 OkHttpClient singleton = INSTANCE.get(); if (null != singleton){ return singleton; } OkHttpClient.Builder builder = new OkHttpClient.Builder(); //定义属性-自行处理 HttpPoolProperties pool = properties.getHttpPool(); if (Objects.nonNull(pool.getCallTimeout())){ builder.callTimeout(pool.getCallTimeout(), TimeUnit.MILLISECONDS); } if (Objects.nonNull(pool.getReadTimeout())){ builder.readTimeout(pool.getReadTimeout(), TimeUnit.MILLISECONDS); } if (Objects.nonNull(pool.getWriteTimeout())){ builder.writeTimeout(pool.getWriteTimeout(), TimeUnit.MILLISECONDS); } if (Objects.nonNull(pool.getConnectTimeout())){ builder.connectTimeout(pool.getConnectTimeout(), TimeUnit.MILLISECONDS); } builder.connectionPool(new ConnectionPool(pool.getMaxIdle(), pool.getKeepAlive(), TimeUnit.MILLISECONDS)); singleton = builder.build(); if (INSTANCE.compareAndSet(null, singleton)){ return singleton; } } }
/** * OkHttp 请求封装 * @param request 请求 * @return 响应结果 * @throws IOException 异常 */ public HttpResponse call(Request request)throws IOException { long startTime = System.currentTimeMillis(); try { Response response = client().newCall(request).execute(); HttpResponse resp; try { resp = new HttpResponse(); resp.setUrl(request.url()); resp.setCode(response.code()); resp.setBody(null == response.body() ? null : Objects.requireNonNull(response.body()).string()); long cost = (System.currentTimeMillis() - startTime) / 1000; if (cost > REQUEST_TIMEOUT) { log.error("[ES-Client]执行Http耗时太长,节点:{},耗时:{}", request.url().host(), cost); throw new RuntimeException("ES执行操作耗时太长,请检查!"); } } catch (Exception e) { log.error(String.format("请求[ES-Client]发生异常,节点:%s,%d", request.url().host(), request.url().port()), e); throw e; } finally { if (null != response) { response.close(); } } return resp; } catch (ConnectException e) { //踢出lost节点 httpTargetPool.disconnect(request.url().host()); throw e; } }
本节仅叙述Elasticsearch的各种查询定义,以及查询客户端的选择,后续将逐步展开,逐步带大家探索如何构建搜索引擎系统。
转载地址:http://hccpi.baihongyu.com/