Query DSL
Elasticsearch以类似于 REST Query DSL 的方式提供了一套完整的java query dsl(Domain Specific Language)。
查询语句构建的factory是 QueryBuilders
。
查询准备就绪之后就可以使用 Search API 了。
要使用 QueryBuilders
只需要在类中引入它们:
import static org.elasticsearch.index.query.QueryBuilders.*;
注意可以使用 QueryBuilder
类中的 toString()
方法方便的打印(调试时)查询语句生成的JSON。
QueryBuilder
可以被用于接受查询语句的任何API中,例如 count
和 search
。
Full text queries
高级全文检索通常在全文本全字段这样的全文查询时使用,邮件的正文就是这样的例如。
它们了解如何分析所查询的字段,并在查询前将每个字段的 analyzer
(或 search_analyzer
)应用于查询字符串中。
该组中的查询语句包括:
match
query-
执行全文检索的标准查询语句,包括模糊匹配、短语匹配和近似匹配。
multi_match
query-
match
query 的多字段版本。 common_terms
query-
一个更加特殊的查询语句,专门为不常用的词准备。
query_string
query-
支持Lucene的语法,允许在条件中使用 AND|OR|NOT 和单语多字段查询。 仅供专业用户使用。
simple_query_string
-
一个
query_string
语法的的更简单且更健壮版本,适合直接开放给用户。
Multi Match Query
multiMatchQuery(
"kimchy elasticsearch", (1)
"user", "message"); (2)
1 | text |
2 | fields |
Term level queries
尽管 full text queries 将在执行之前分析查询语句, 但 term-level queries 会按照存储在反向索引中的确切词进行操作。
这些查询语句通常使用在数字、日期和枚举等结构化数据,而不是全字符串字段。 当然也允许在分析过程之前使用 low-level 查询语句。
这一组中的查询有:
term
query-
检索指定字段包含指定条件的文档。
terms
query-
检索指定字段包含指定条件中的任意一个的文档。
range
query-
检索指定字段包含指定范围内的值(日期、数字或字符串)的文档。
exists
query-
检索指定字段是否包含非空值的文档。
prefix
query-
查找指定字段是以指定的条件作为开头的文档。
wildcard
query-
根据通配符匹配指定字段来检索文档,支持单字符匹配(
?
)和多字符匹配(*
)。 regexp
query-
根据正则表达式匹配指定字段来检索文档。
fuzzy
query-
根据模糊相似词检索文档。 模糊度是根据 莱文斯坦距离 1或2来衡量的 。
type
query-
根据指定类型检索文档。
ids
query-
根据指定类型和id列表检索文档。
Range Query
查看 Range Query
rangeQuery("price") (1)
.from(5) (2)
.to(10) (3)
.includeLower(true) (4)
.includeUpper(false); (5)
1 | 字段 |
2 | 开始 |
3 | 结束 |
4 | 是否包含最小值 |
5 | 是否包含最大值 |
// 一种简单的写法是使用 gte(greater than or equal), gt, lt 或 lte(less than or equal)
rangeQuery("age") (1)
.gte("10") (2)
.lt("20"); (3)
1 | field |
2 | 等价于 from(10) 和 includeLower(true) 两个条件 |
3 | 等价于 to(20) 和 includeUpper(false) 两个条件 |
Ids Query
查看 Ids Query
idsQuery("my_type", "type2")
.addIds("1", "4", "100");
idsQuery() (1)
.addIds("1", "4", "100");
1 | type 是可选项 |
Compound queries
组合查询可以将其它组合查询,以及其它单独的查询语句合并到一起,并将结果和匹配分数组合起来。 它可以改变它们的行为,或是将查询转换为filter context。
这一组中的查询有:
constant_score
query-
包含其它查询的查询,但却以filter context的形式执行该语句。所有匹配到的文档都会分配相同的 "constant"
_score
。 bool
query-
使用
must
,should
,must_not
, 或filter
可以将多个分支或组合查询语句组合到一起。 其中must
和should
条件的得分会合并到一起,这是大多数时候使用的条件; 而更好的办法是使用must_not
和filter
,这样它们会在 filter context 中执行。 dis_max
query-
一个接受多个查询语句的查询,匹配到任何查询子句的文档都会返回。 虽然
bool
语句已经将所有匹配结果的得分组合了起来,但dis_max
的得分却是单条语句匹配的最高得分。 function_score
query-
使用函数修改主查询返回的分数,以考虑流行性、失效性、距离或使用脚本实现的自定义算法等因素。
boosting
query-
查询条件将会分为正匹配和负匹配。
positive
(正确)匹配到的文档将会加分,negative
(负面)匹配得到的文档将会减分。
Constant Score Query
constantScoreQuery(
termQuery("name","kimchy")) (1)
.boost(2.0f); (2)
1 | your query |
2 | query score |
Bool Query
查看 Bool Query
boolQuery()
.must(termQuery("content", "test1")) (1)
.must(termQuery("content", "test4")) (1)
.mustNot(termQuery("content", "test2")) (2)
.should(termQuery("content", "test3")) (3)
.filter(termQuery("content", "test5")); (4)
1 | must query |
2 | must not query |
3 | should query |
4 | 绝对匹配,不参与评分。 |
Dis Max Query
disMaxQuery()
.add(termQuery("name", "kimchy")) (1)
.add(termQuery("name", "elasticsearch")) (2)
.boost(1.2f) (3)
.tieBreaker(0.7f); (4)
1 | add your queries |
2 | add your queries |
3 | boost factor |
4 | tie breaker |
Function Score Query
想要使用 ScoreFunctionBuilders
只需要在类中引入:
import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.*;
FilterFunctionBuilder[] functions = {
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
matchQuery("name", "kimchy"), (1)
randomFunction()), (2)
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
exponentialDecayFunction("age", 0L, 1L)) (3)
};
functionScoreQuery(functions);
1 | Add a first function based on a query |
2 | And randomize the score based on a given seed |
3 | Add another function based on the age field |
Joining queries
在Elasticsearch这样的分布式系统中使用SQL风格的关联语句对性能的损耗是非常大的。 作为替代,Elasticsearch设计了两种支持水平拓展的关联操作。
nested
query-
文档可能包含
nested
类型的字段。 这些字段用于索引对象数组,其中每个对象都可以作为独立文档进行查询(使用nested
查询)。 has_child
和has_parent
查询-
同一索引之中的文档可以存在父子关系。
has_child
查询会返回子文档匹配的父文档,而has_parent
查询则会返回父文档匹配的子文档。
Nested Query
查看 Nested Query
nestedQuery(
"obj1", (1)
boolQuery() (2)
.must(matchQuery("obj1.name", "blue"))
.must(rangeQuery("obj1.count").gt(5)),
ScoreMode.Avg); (3)
1 | 嵌套文档的路径 |
2 | 查询中使用的所有字段都必须使用完整路径 |
3 | 评分模式支持: ScoreMode.Max , ScoreMode.Min , ScoreMode.Total , ScoreMode.Avg 或 ScoreMode.None |
Has Child Query
使用 has_child
查询的时候有一点很重要的就是使用 PreBuiltTransportClient
而不是普通的client。
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9300)));
否则父子链接模块将不会被加载,同样的 transport client
中也不能使用 has_child
查询语句。
JoinQueryBuilders.hasChildQuery(
"blog_tag", (1)
termQuery("tag","something"), (2)
ScoreMode.None); (3)
1 | child type to query against |
2 | query |
3 | 评分模式支持: ScoreMode.Avg , ScoreMode.Max , ScoreMode.Min , ScoreMode.None 或 ScoreMode.Total |
Has Parent Query
查看 Has Parent
使用 has_parent
查询的时候有一点很重要的就是使用 PreBuiltTransportClient
而不是普通的client:
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9300)));
否则父子链接模块将不会被加载,同样的 transport client
中也不能使用 has_child
查询语句。
JoinQueryBuilders.hasParentQuery(
"blog", (1)
termQuery("tag","something"), (2)
false); (3)
1 | parent type to query against |
2 | query |
3 | 是否将父文档匹配分数传递给子文档 |
Geo queries
Elasticsearch支持两种类型的地理位置数据:支持经纬度的 geo_point
,以及支持点、线、圆、多边形等的 geo_shape
。
该组中的查询语句包括:
geo_shape
查询-
可以匹配坐标与指定区域相交、不相交或包含的地理位置。
geo_bounding_box
查询-
可以匹配坐标在矩形区域的地理位置。
geo_distance
查询-
可以查询指定坐标为中心点指定距离内的地理位置。
geo_polygon
查询-
可以查询坐标在多边形范围内的地理位置。
GeoShape Query
Note: geo_shape
类型使用 Spatial4J
和 JTS
两种依赖。
因此,必须将 Spatial4J
和 JTS
添加到 classpath中才能使用这种类型:
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.7</version> (1)
</dependency>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.15.0</version> (2)
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
</exclusion>
</exclusions>
</dependency>
1 | 在 Maven Central 中查看更新 |
2 | 在 Maven Central 中查看更新 |
// Import ShapeRelation and ShapeBuilder
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
GeoShapeQueryBuilder qb = geoShapeQuery(
"pin.location", (1)
new MultiPointBuilder( (2)
new CoordinatesBuilder()
.coordinate(0, 0)
.coordinate(0, 10)
.coordinate(10, 10)
.coordinate(10, 0)
.coordinate(0, 0)
.build()));
qb.relation(ShapeRelation.WITHIN); (3)
1 | field |
2 | shape |
3 | 关系可以是 ShapeRelation.CONTAINS , ShapeRelation.WITHIN , ShapeRelation.INTERSECTS 或 ShapeRelation.DISJOINT |
// Using pre-indexed shapes
GeoShapeQueryBuilder qb = geoShapeQuery(
"pin.location", (1)
"DEU", (2)
"countries"); (3)
qb.relation(ShapeRelation.WITHIN) (4)
.indexedShapeIndex("shapes") (5)
.indexedShapePath("location"); (6)
1 | field |
2 | 包含pre-indexed形状的文档ID |
3 | 包含pre-indexed形状的index type |
4 | relation |
5 | 包含pre-indexed形状的index名,默认是shapes |
6 | 包含pre-indexed形状的字段名,默认是’shape' |
Geo Bounding Box Query
geoBoundingBoxQuery("pin.location") (1)
.setCorners(40.73, -74.1, (2)
40.717, -73.99); (3)
1 | field |
2 | 矩形左上角的坐标点 |
3 | 矩形右上角的坐标点 |
Geo Distance Query
geoDistanceQuery("pin.location") (1)
.point(40, -70) (2)
.distance(200, DistanceUnit.KILOMETERS); (3)
1 | field |
2 | 中心点坐标 |
3 | 和中心点的距离 |
Specialized queries
该组查询中包含以下这些不适用于其它查询的语句:
more_like_this
query-
这个查询语句可以检索出和指定的文本、文档或文档集合相似的文档。
script
query-
这个查询语句可以将脚本作为过滤器来适用。请查看
function_score
query 。 percolate
query-
This query finds percolator queries based on documents.
wrapper
query-
可以接受Json和Yaml类型语句的查询。
More Like This Query
String[] fields = {"name.first", "name.last"}; (1)
String[] texts = {"text like this one"}; (2)
moreLikeThisQuery(fields, texts, null)
.minTermFreq(1) (3)
.maxQueryTerms(12); (4)
1 | fields |
2 | text |
3 | 忽略阈值 |
4 | 生成语句条件的最大字数 |
Script Query
查看 Script Query
scriptQuery(
new Script("doc['num1'].value > 1") (1)
);
1 | 定义脚本 |
如果数据节点上已经存储了脚本,例如叫 myscript.painless
:
doc['num1'].value > params.param1
你就可以这样使用它:
Map<String, Object> parameters = new HashMap<>();
parameters.put("param1", 5);
scriptQuery(new Script(
ScriptType.STORED, (1)
null, (2)
"myscript", (3)
singletonMap("param1", 5))); (4)
1 | Script type: either ScriptType.FILE , ScriptType.INLINE or ScriptType.INDEXED |
2 | Scripting engine |
3 | Script name |
4 | Parameters as a Map<String, Object> |
Percolate Query
查看: * Percolate Query
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9300)));
在使用 percolate
查询之前,应该添加 percolate
的映射,并且应该对包含 percolate
查询的文档建立索引:
// create an index with a percolator field with the name 'query':
client.admin().indices().prepareCreate("myIndexName")
.addMapping("_doc", "query", "type=percolator", "content", "type=text")
.get();
//This is the query we're registering in the percolator
QueryBuilder qb = termQuery("content", "amazing");
//Index the query = register it in the percolator
client.prepareIndex("myIndexName", "_doc", "myDesignatedQueryName")
.setSource(jsonBuilder()
.startObject()
.field("query", qb) // Register the query
.endObject())
.setRefreshPolicy(RefreshPolicy.IMMEDIATE) // Needed when the query shall be available immediately
.get();
查询语句会在 myDesignatedQueryName 的下面建立索引。
为了对照已注册的查询语句检查文档,可以使用如下代码:
//Build a document to check against the percolator
XContentBuilder docBuilder = XContentFactory.jsonBuilder().startObject();
docBuilder.field("content", "This is amazing!");
docBuilder.endObject(); //End of the JSON root object
PercolateQueryBuilder percolateQuery = new PercolateQueryBuilder("query", "_doc", BytesReference.bytes(docBuilder));
// Percolate, by executing the percolator query in the query dsl:
SearchResponse response = client().prepareSearch("myIndexName")
.setQuery(percolateQuery))
.get();
//Iterate over the results
for(SearchHit hit : response.getHits()) {
// Percolator queries as hit
}
Span queries
Span queries 是一种低级别的位置查询语句,它提供对排序和相似度更专业的控制。 通常用在法律文件或专利这样非常具体的查询。
Span queries不能和non-span queries(span_multi
query 是个例外)混合使用。
该组中包括以下查询:
span_term
query-
等同于
term
query ,但用于其它跨度查询。 span_multi
queryspan_first
query-
接收另一个 span query,它的匹配项必须出现在该字段的前 N 个位置。
span_near
query-
接受在指定距离内其它的span queries,并且可以是以相同的顺序。
span_or
query-
将多个span queries组合起来,并返回任何匹配的文档。
span_not
query-
包含其它span query,并排除匹配的文档。
span_containing
query-
接受一个span queries列表,但只返回两个条件都匹配的文档。
span_within
query-
只要span query落在由其它span queries中,就会返回span query的结果。
Span Multi Term Query
spanMultiTermQueryBuilder(
prefixQuery("user", "ki")); (1)
1 | 支持任何继承 MultiTermQueryBuilder 的类,比如 FuzzyQueryBuilder ,
PrefixQueryBuilder , RangeQueryBuilder , RegexpQueryBuilder 或 WildcardQueryBuilder . |
Span Near Query
spanNearQuery(
spanTermQuery("field","value1"), (1)
12) (2)
.addClause(spanTermQuery("field","value2")) (3)
.addClause(spanTermQuery("field","value3")) (4)
.inOrder(false); (5)
1 | span queries 条件 |
2 | 不匹配的最大数量 |
3 | span queries 条件 |
4 | span queries 条件 |
5 | 匹配之后是否需要排序 |
Span Or Query
spanOrQuery(spanTermQuery("field","value1")) (1)
.addClause(spanTermQuery("field","value2")) (2)
.addClause(spanTermQuery("field","value3")); (3)
1 | span queries 条件 |
Span Not Query
spanNotQuery(
spanTermQuery("field","value1"), (1)
spanTermQuery("field","value2")); (2)
1 | 需要进行过滤的 span query |
2 | 需要排除的 span query |
Span Containing Query
spanContainingQuery(
spanNearQuery(spanTermQuery("field1","bar"), 5) (1)
.addClause(spanTermQuery("field1","baz"))
.inOrder(true),
spanTermQuery("field1","foo")); (2)
1 | 大 的部分 |
2 | 小 的部分 |