11.3. 搜索
使用 Ickle 查询语言在 Library 和 Remote Client-Server 模式中创建关系和全文本查询。
要使用 API,首先获取 QueryFactory 到缓存,然后调用 .create ()
方法,传递字符串以便在查询中使用。每个 QueryFactory
实例都绑定到与 Search
相同的 缓存
实例,但它是一个无状态和 thread-safe 对象,可用于并行创建多个查询。
例如:
// Remote Query, using protobuf QueryFactory qf = org.infinispan.client.hotrod.Search.getQueryFactory(remoteCache); Query q = qf.create("from sample_bank_account.Transaction where amount > 20"); // Embedded Query using Java Objects QueryFactory qf = org.infinispan.query.Search.getQueryFactory(cache); Query q = qf.create("from com.acme.Book where price > 20"); // Execute the query QueryResult<Book> queryResult = q.execute();
查询将始终以单个实体类型为目标,并在单个缓存的内容上评估。不支持对多个缓存运行查询,或创建以多个实体类型(连接)为目标的查询。
执行查询并获取结果非常简单,就像调用 Query
对象的 run ()
方法一样简单。执行之后,在同一实例上调用 run ()
将重新执行查询。
11.3.1. 分页
您可以使用 Query.maxResults (int maxResults)
限制返回的结果数量。这可与 Query.startOffset (long startOffset)
一起使用,来实现结果集的分页。
// sorted by year and match all books that have "clustering" in their title // and return the third page of 10 results Query<Book> query = queryFactory.create("FROM com.acme.Book WHERE title like '%clustering%' ORDER BY year").startOffset(20).maxResults(10)
11.3.2. Hits 的数量
QueryResult
对象具有 .hitCount ()
方法,可以返回查询的结果总数,而不考虑任何分页参数。因为性能的原因,点击数仅适用于索引的查询。
11.3.3. 迭代
Query
对象具有 .iterator
() 方法,可以完全获得结果。它返回一个在使用后必须关闭的 CloseableIterator
实例。
远程查询的迭代支持当前有限,因为它在迭代前首先获取客户端的所有条目。
11.3.4. 使用 Named Query 参数
可以不必为每个执行构建一个新的 Query 对象,而是在查询中包含命名参数,这些参数可以在执行前使用实际值替换。这允许定义一次查询,并可以有效地执行多次。参数只能在操作器的右侧使用,并通过提供由 org.infinispan.query.dsl.Expression.param (String paramName)
方法生成的对象来创建查询时定义。定义参数后,可以通过调用 Query.setParameter (parameterName, value)
或 Query.setParameters (parameterMap)
来设置参数,如以下示例所示。
QueryFactory queryFactory = Search.getQueryFactory(cache); // Defining a query to search for various authors and publication years Query<Book> query = queryFactory.create("SELECT title FROM com.acme.Book WHERE author = :authorName AND publicationYear = :publicationYear").build(); // Set actual parameter values query.setParameter("authorName", "Doe"); query.setParameter("publicationYear", 2010); // Execute the query List<Book> found = query.list();
或者,您可以提供一个实际参数值映射以一次性设置多个参数:
一次设置多个命名参数
Map<String, Object> parameterMap = new HashMap<>(); parameterMap.put("authorName", "Doe"); parameterMap.put("publicationYear", 2010); query.setParameters(parameterMap);
在首次使用参数执行查询时,执行查询解析、验证和执行规划工作的主要部分。与使用恒定值而不是查询参数类似的查询相比,后续执行期间不会重复这一工作,从而提高性能。
11.3.5. Ickle Query Language Parser Syntax
Ickle 查询语言是 JPQL 查询语言的小子集,具有一些全文本扩展。
解析器语法有一些值得注意的规则:
- 空格并不重要。
- 字段名称不支持通配符。
- 必须始终指定字段名称或路径,因为没有默认字段。
-
&&
和||
在全文本和 JPA predicates 中都接受AND
或OR
。 -
!
可以被使用,而不是。
-
缺少布尔值运算符解释为
OR
。 - 字符串术语必须用单引号或双引号括起。
- Fuzziness 和 boosting 没有被任意顺序接受;fuzziness 始终是首先接受的。
-
!=
被接受,而不是 <>
。 -
boosting 无法应用到 >,
>
;=, &
lt;
, HBAC operators。范围可用于实现相同的结果。
11.3.5.1. 过滤 Operator
Ickle 支持许多可用于索引和非索引字段的过滤运算符。
Operator | 描述 | Example |
---|---|---|
in | 检查左侧运算对象是否等于所给值集合中的一个元素。 | FROM Book WHERE isbn IN ('ZZ', 'X1234') |
like | 检查左侧参数(预期为 String)是否匹配 JPA 规则之后的通配符模式。 | FROM Book WHERE 标题 LIKE '%Java%' |
= | 检查 left 参数是否与给定值完全匹配 | FROM Book WHERE name = 'Programming Java' |
!= | 检查 left 参数与给定值不同 | FROM Book WHERE 语言 != ' English' |
> | 检查 left 参数是否大于给定值。 | FROM Book WHERE price > 20 |
>= | 检查 left 参数是否大于或等于给定值。 | FROM Book WHERE price >= 20 |
< | 检查 left 参数是否小于给定值。 | FROM Book WHERE year < 2012 |
⇐ | 检查 left 参数是否小于或等于给定值。 | FROM Book WHERE price 了 50 |
between | 检查 left 参数是否在给定的范围限值之间。 | FROM Book WHERE 价格 BETWEEN 50 AND 100 |
11.3.5.2. 布尔值条件
以下示例中演示了多个属性条件和逻辑组合(和
)和 disjunction (或
)运算符,以创建更复杂的条件。布尔值运算符的已知运算符优先级规则适用于此处,因此操作器的顺序无关。这里 和
运算符的优先级比 高,即使先调用 或
。
# match all books that have "Data Grid" in their title # or have an author named "Manik" and their description contains "clustering" FROM com.acme.Book WHERE title LIKE '%Data Grid%' OR author.name = 'Manik' AND description like '%clustering%'
布尔值负值在逻辑运算符之间具有最高优先级,并且只适用于下一个简单的属性条件。
# match all books that do not have "Data Grid" in their title and are authored by "Manik" FROM com.acme.Book WHERE title != 'Data Grid' AND author.name = 'Manik'
11.3.5.3. 嵌套条件
通过括号更改逻辑运算符的优先级:
# match all books that have an author named "Manik" and their title contains # "Data Grid" or their description contains "clustering" FROM com.acme.Book WHERE author.name = 'Manik' AND ( title like '%Data Grid%' OR description like '% clustering%')
11.3.5.4. 选择属性
在某些用例中,如果应用实际使用了一小部分属性,则返回整个域对象是过量的,特别是在域实体有嵌入式实体时。查询语言允许您指定属性(或属性路径)的子集来返回 - 投射。如果使用投射,则 QueryResult.list ()
不会返回整个域实体,而是返回 Object[]
列表
,则数组中的每个插槽都与投射属性对应。
# match all books that have "Data Grid" in their title or description # and return only their title and publication year SELECT title, publicationYear FROM com.acme.Book WHERE title like '%Data Grid%' OR description like '%Data Grid%'
11.3.5.5. 排序
使用 ORDER BY
子句,根据一个或多个属性或属性路径对结果进行排序。如果指定了多个排序条件,则顺序将指定其优先级。
# match all books that have "Data Grid" in their title or description # and return them sorted by the publication year and title FROM com.acme.Book WHERE title like '%Data Grid%' ORDER BY publicationYear DESC, title ASC
11.3.5.6. 分组和聚合
Data Grid 能够根据一组分组字段并构造来自每个组的结果聚合来对查询结果进行分组,方法是将聚合应用到每个组中的值集合。分组和聚合只能应用到投射查询(在 SELECT 子句中带有一个或多个字段)。
支持的聚合有: avg、sum、count、max、min。
组分组字段通过 GROUP BY
子句指定,并且用于定义分组字段的顺序无关。投射中选择的所有字段都必须分组字段,否则必须使用下面描述的分组功能之一来聚合它们。项目字段可以聚合,并同时用于分组。选择仅分组字段但没有聚合字段的查询是法律的。附录示例:作者对手册进行分组,并计算它们。
SELECT author, COUNT(title) FROM com.acme.Book WHERE title LIKE '%engine%' GROUP BY author
一个投射查询,所有选择的字段都应用了聚合功能,且无法用于分组的字段。在这种情况下,聚合将全局计算,就像有一个全局组一样。
11.3.5.7. 聚合
以下聚合功能可应用到字段:
-
avg ()
- 计算一组数字的平均数量。接受的值是原始数字和java.lang.Number
的实例。结果以java.lang.Double
表示。如果没有非 null 值,则结果为null
。 -
count ()
- 计算非null 行的数量并返回java.lang.Long
。如果没有非 null 值,则结果为
0。 -
max ()
- 返回找到的最大值。接受的值必须是java.lang.Comparable
的实例。如果没有非 null 值,则结果为null
。 -
min ()
- 返回找到的最小值。接受的值必须是java.lang.Comparable
的实例。如果没有非 null 值,则结果为null
。 -
sum ()
- 计算一组数字的总和。如果没有非 null 值,则结果为null
。下表根据指定字段显示返回类型。
字段类型 | 返回类型 |
---|---|
不可或缺(除 BigInteger) | Long |
float 或 Double | å�Œ |
BigInteger | BigInteger |
BigDecimal | BigDecimal |
11.3.5.8. 使用分组和聚合评估查询
聚合查询可以包含过滤条件,如常规查询。可以在两个阶段执行过滤:在分组操作之前和之后执行。在执行分组操作之前,定义的所有过滤器条件都将应用到缓存条目(而不是最终投射)。这些过滤器条件可以引用查询的实体类型的任何字段,旨在限制要作为分组阶段输入的数据集。调用
groupBy ()
方法后定义的所有过滤器条件将应用到投射结果和分组操作。这些过滤器条件可以引用任何 groupBy ()
字段或聚合的字段。允许引用在 select 子句中指定的聚合字段,但禁止引用非aggregated 和 non-grouping 字段。在此阶段过滤将根据其属性减少组量。排序也可以指定,类似于常见的查询。排序操作在分组操作后执行,并可引用任何 groupBy ()
字段或聚合字段。
11.3.5.9. 使用全文本搜索
11.3.5.9.1. fuzzy Queries
要执行模糊查询,请添加 ~
和整数,代表术语后面的术语的距离。例如
FROM sample_bank_account.Transaction WHERE description : 'cofee'~2
11.3.5.9.2. 范围查询
要执行范围查询,请在大括号内定义给定边界,如下例所示:
FROM sample_bank_account.Transaction WHERE amount : [20 to 50]
11.3.5.9.3. 短语查询
可以通过用引号括起来来搜索一组词语,如下例所示:
FROM sample_bank_account.Transaction WHERE description : 'bus fare'
11.3.5.9.4. 代理查询
要执行相似查询,请在特定距离中查找两个术语,请在短语后添加一个 ~
和距离。例如,以下示例将查找取消和费用的词语,只要它们不多于 3 个词语:
FROM sample_bank_account.Transaction WHERE description : 'canceling fee'~3
11.3.5.9.5. 通配符查询
要搜索"文本"或"test",请使用 ?
单字符通配符搜索:
FROM sample_bank_account.Transaction where description : 'te?t'
要搜索 "test", "tests" 或 "tester",请使用 *
多字符通配符搜索:
FROM sample_bank_account.Transaction where description : 'test*'
11.3.5.9.6. 正则表达式查询
通过在 /
之间指定模式,可以执行正则表达式查询。Ickle 使用 Lucene 的正则表达式语法,因此可以搜索单词 moat
或 boat
:
FROM sample_library.Book where title : /[mb]oat/
11.3.5.9.7. 提升查询
通过在术语后面添加 ^
来提高给定查询的相关性,可以提高术语的提升因素越高。例如,要搜索包含 beer 和 wine 较高的相关标题(3 倍),可以使用以下内容:
FROM sample_library.Book WHERE title : beer^3 OR wine