Elasticsearch 设计模式—建造者模式
建造者模式
构造者模式,或称建造者模式(Builder Pattern).
概念
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 [构建与表示分离,同构建不同表示]
UML 图
一般来说, 构造者模式会涉及到四个角色:
-
抽象建造者(Builder)角色
给 出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者 (ConcreteBuilder)角色
-
具体建造者(ConcreteBuilder)角色
担任这个角色的是与应用程序紧密相关的一些类,它们在应用程序调用下创建产品的实例。这个角色要完成的任务包括:1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例
-
导演者(Director)角色
担任这个角色的类调用具体建造者角色以创建产品对象。应当指出的是,导演者角色并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者角色
-
产品(Product)角色
产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
Elasticsearch 对于建造者模式的应用
众所周知,Elasticsearch 提供了及其丰富的查询 API,而这些查询 API 的构建核心就是利用建造者模式来完成的,可以说 Elasticsearch 是我见过将建造者模式应用的最好
和最丰富最完美的一个架构.接下来我们就看看 Elasticsearch 是如何在自己的系统里使用建造者模式.
抽象建造者(Builder)角色
QueryBuilder 是构建所有查询的入口,源码如下:
public interface QueryBuilder extends NamedWriteable, ToXContentObject {
/**
* Converts this QueryBuilder to a lucene {@link Query}.
* Returns <tt>null</tt> if this query should be ignored in the context of
* parent queries.
*
* @param context additional information needed to construct the queries
* @return the {@link Query} or <tt>null</tt> if this query should be ignored upstream
*/
Query toQuery(QueryShardContext context) throws IOException;
/**
* Converts this QueryBuilder to an unscored lucene {@link Query} that acts as a filter.
* Returns <tt>null</tt> if this query should be ignored in the context of
* parent queries.
*
* @param context additional information needed to construct the queries
* @return the {@link Query} or <tt>null</tt> if this query should be ignored upstream
*/
Query toFilter(QueryShardContext context) throws IOException;
/**
* Sets the arbitrary name to be assigned to the query (see named queries).
* Implementers should return the concrete type of the
* {@link QueryBuilder} so that calls can be chained. This is done
* automatically when extending {@link AbstractQueryBuilder}.
*/
QueryBuilder queryName(String queryName);
/**
* Returns the arbitrary name assigned to the query (see named queries).
*/
String queryName();
/**
* Returns the boost for this query.
*/
float boost();
/**
* Sets the boost for this query. Documents matching this query will (in addition to the normal
* weightings) have their score multiplied by the boost provided.
* Implementers should return the concrete type of the
* {@link QueryBuilder} so that calls can be chained. This is done
* automatically when extending {@link AbstractQueryBuilder}.
*/
QueryBuilder boost(float boost);
/**
* Returns the name that identifies uniquely the query
*/
String getName();
/**
* Rewrites this query builder into its primitive form. By default this method return the builder itself. If the builder
* did not change the identity reference must be returned otherwise the builder will be rewritten infinitely.
*/
default QueryBuilder rewrite(QueryRewriteContext queryShardContext) throws IOException {
return this;
}
/**
* Rewrites the given query into its primitive form. Queries that for instance fetch resources from remote hosts or
* can simplify / optimize itself should do their heavy lifting during {@link #rewrite(QueryRewriteContext)}. This method
* rewrites the query until it doesn't change anymore.
* @throws IOException if an {@link IOException} occurs
*/
static QueryBuilder rewriteQuery(QueryBuilder original, QueryRewriteContext context) throws IOException {
QueryBuilder builder = original;
for (QueryBuilder rewrittenBuilder = builder.rewrite(context); rewrittenBuilder != builder;
rewrittenBuilder = builder.rewrite(context)) {
builder = rewrittenBuilder;
}
return builder;
}
}
该接口用来规范定义想要构造一个查询构造器的标准条件,是一个最顶层的抽象构造器接口:
- boost
- queryName
而其子类 AbstractQueryBuilder 则是默认实现了接口中的一些规范,两者共同充当建造者模式中的抽象建造者(Builder)角色.
具体建造者(ConcreteBuilder)角色
Elasticsearch 中拥有大量的具体的建造者角色,这些具体的建造者角色就是 Elasticsearch 根据不同的查询场景的构造者,比如:BoolQueryBuilder,MatchPhraseQueryBuilder 等
这里只拿 BoolQueryBuilder 进行说明,部分源码如下:
public BoolQueryBuilder must(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
throw new IllegalArgumentException("inner bool query clause cannot be null");
}
mustClauses.add(queryBuilder);
return this;
}
public BoolQueryBuilder filter(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
throw new IllegalArgumentException("inner bool query clause cannot be null");
}
filterClauses.add(queryBuilder);
return this;
}
public BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
throw new IllegalArgumentException("inner bool query clause cannot be null");
}
mustNotClauses.add(queryBuilder);
return this;
}
public BoolQueryBuilder should(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
throw new IllegalArgumentException("inner bool query clause cannot be null");
}
shouldClauses.add(queryBuilder);
return this;
}
从源码中可以看到, 针对不同的条件,可以使用不同的方法进行构造布尔查询。
导演者(Director)角色
Elasticsearch 中充当导演者角色的类是 SearchRequestBuilder,其自身也是一个构造器,同时也是一个导演者(Director)角色,内部持有具体的构造器来完成
具体的构建过程.
产品(Director)角色
Elasticsearch 中充当导演者角色的就是这些构造器本身
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于