7.4. 将实体映射到索引结构
7.4.1. 映射实体 复制链接链接已复制到粘贴板!
索引实体所需的所有元数据信息都通过注释进行描述,因此无需 XML 映射文件。您仍然可以将 Hibernate 映射文件用于基本 Hibernate 配置,但是必须通过注释来表示 Hibernate Search 特定配置。
7.4.1.1. 基本映射 复制链接链接已复制到粘贴板!
让我们从最常用于映射实体的注释开始。
基于 Lucene 的查询 API 使用以下常见注解来映射实体:
- @Indexed
- @field
- @NumericField
- @Id
7.4.1.2. @Indexed 复制链接链接已复制到粘贴板!
最重要的是,我们必须将持久类声明为可索引。这可以通过使用 @Indexed 为类添加注解(索引流程将忽略未注释 @Indexed 的 所有实体):
@Entity
@Indexed
public class Essay {
...
}
@Entity
@Indexed
public class Essay {
...
}
您可以选择指定 @Indexed 注释的 index 属性,以更改索引的默认名称。
7.4.1.3. @field 复制链接链接已复制到粘贴板!
对于实体的每个属性(或属性),您可以描述如何对其进行索引。默认(不存在)表示索引过程中会忽略该属性。
在 Hibernate Search 5 之前,只有通过 @NumericField 明确请求时,才会选择数字字段编码。从 Hibernate Search 5 开始,系统将自动为数字类型选择此编码。为避免数字编码,您可以通过 @Field.bridge 或 明确指定非数字字段网桥。软件包 @Field Bridgeorg.hibernate.search.bridge.builtin 包含一组网桥,这些网桥编号编码为字符串,如 org.hibernate.search.bridge.builtin.IntegerBridge。
@field 确实将属性声明 为索引,并允许通过设置以下一个或多个属性来配置索引过程的多个方面:
-
Name :describe 在哪个名称下,该属性应存储在 Lucene 文档中。默认值为属性名称(遵循 JavaBeans 约定) -
存储:描述属性是否存储在 Lucene 索引中。您可以存储值Store.YES(在索引中消耗更多空间,但允许 投射,以压缩方式存储 Store.COMPRESS(这确实消耗更多 CPU),或者避免任何存储Store.NO(这是默认值)。存储属性时,您可以从 Lucene 文档检索其原始值。这与元素是否索引无关。 index:描述属性是否索引。不同的值是 index.NO,这表示它不会被索引,不能被查询和Index.YES找到,即元素会被索引并可以搜索。默认值为Index.YES。index. no在不需要可搜索属性但应该可用于投射的情形中,将非常有用。注意index.NO与 Analyze.YES或Norms.YES结合使用,因为分析和强制要求对该属性进行索引。分析:确定属性是否被分析(Analyze.YES)还是不分析(Analyze.NO)。默认值为 Analyze.YES。注意是否要分析属性取决于您是否希望按原样搜索元素,或按其包含的词语搜索。分析文本字段会有意义,但可能不是日期字段。
注意不得 分析用于排序的字段。
-
强制:描述索引时间提升信息应存储(Norms.YES)还是不存储(Norms.NO)。不存储存储会节省大量内存,但没有任何索引时间提高可用信息。默认值为Norms.YES。 termVector:描述术语频率对的集合。这个属性允许在索引过程中将术语向量存储在文档中。默认值为TermVector.NO。此属性的不同值有:
Expand 值 定义 TermVector.YES
存储每个文档的术语向量。这会生成两个同步的数组,一个包含文档术语,另一个包含术语的频率。
TermVector.NO
不要存储术语向量。
TermVector.WITH_OFFSETS
存储术语向量和令牌偏移信息。这与 TermVector.YES 加上它包含术语的起始和结束偏移位置信息相同。
TermVector.WITH_POSITIONS
存储术语向量和令牌位置信息。这与 TermVector.YES 相同,还包含每一次在文档中出现某个术语的规范。
TermVector.WITH_POSITION_OFFSETS
存储术语向量、令牌位置和偏移信息。这是 YES、WITH_OFFSETS 和 WITH_POSITIONS 的组合。
indexNullAs: Per default null 值将被忽略且未索引。不过,您可以使用indexNullAs指定一个字符串,该字符串将被插入为null值的令牌。默认情况下,此值设置为Field。DO_NOT_INDEX_NULL表示不应索引null值。您可以将这个值设置为Field.DEFAULT_NULL_TOKEN,以指示应使用默认的空令牌。可以使用hibernate.search.default_null_token在配置中指定此默认空令牌。如果未设置此属性,并且指定了Field.DEFAULT_NULL_TOKEN,则字符串 "null" 将用作默认值。注意使用
indexNullAs参数时,务必要在搜索查询中使用相同的令牌来搜索null值。此外,建议仅在未分析的字段(分析.NO)中使用此功能。警告在实施自定义 FieldBridge 或 TwoWayFieldBridge 时,开发人员可以处理 null 值的索引(请参阅 JavaDocs LuceneOptions.indexNullAs())。
7.4.1.4. @NumericField 复制链接链接已复制到粘贴板!
@Field 有一个相应的注释,名为 @NumericField,其范围与 @Field 或 @DocumentId 相同。它可用于 Integer、Long、Float 和 Double 属性。在索引时,将使用 Trie 结构对该值进行索引。当属性索引为数字字段时,它实现了有效的范围查询和排序,与对标准 @Field 属性执行相同的查询相比,它实现了高效的范围查询和排序。@NumericField 注释接受以下参数:
| 值 | 定义 |
|---|---|
| forField | (可选)指定将索引为数字的相关 @Field 的名称。只有 属性包含超过 @Field 声明时,才强制使用它 |
| exactStep | (可选)更改 Trie 结构存储在索引中的方式。较小的精度Steps会导致更多磁盘空间使用量、更快的范围和排序查询。较大的值会导致使用空间减少,范围查询性能更接近普通 @Fields 中的范围查询。默认值为 4。 |
@NumericField 仅支持 Double、Long、Integer 和 Float。其他数字类型无法利用 Lucene 中的类似功能,因此其余类型应使用默认或自定义 TwoWayFieldBridge 进行字符串编码。
假设您可以在类型转换过程中处理近似值,可以使用自定义 NumericFieldBridge:
示例:定义自定义数字FieldBridge
7.4.1.5. @Id 复制链接链接已复制到粘贴板!
最后,实体的 id (识别符)属性是 Hibernate Search 使用的特殊属性,用于确保给定实体的索引唯一性。按照设计,必须存储 id,且不能进行令牌化。要将属性标记为索引标识符,可使用 @DocumentId 注释。如果您使用的是 Jakarta Persistence 并且指定了 @Id,您可以省略 @DocumentId。选定的实体标识符也可用作文档标识符。
Infinispan Query 使用实体的 id 属性来确保索引唯一标识。按照设计,ID 会存储,且不得转换为令牌。要将属性标记为索引 ID,可使用 @DocumentId 注释。
示例:指定索引的属性
上例定义了四个字段的索引: id、Abs tract、文本 和 评级。请注意,默认情况下字段名称没有大写,符合 JavaBean 规范。grade 字段标为数字,其精确步骤略大于默认值。
7.4.1.6. 映射属性多次 复制链接链接已复制到粘贴板!
有时,您需要为每个索引多次映射一个属性,索引策略略有不同。例如,根据字段排序查询需要取消分析字段。要按此属性上的词语搜索,仍需要对它进行索引 - 旦分析过,一旦未分析一次。@Fields 允许您实现此目标。
示例:使用 @Fields 映射多个属性时间
在本例中,字段 概述 被索引两次,一次以令牌化的方式作为 概述,一次是以未令牌的方式作为 summary_forSort 索引。
7.4.1.7. 嵌入式和关联对象 复制链接链接已复制到粘贴板!
可以将关联的对象和嵌入式对象作为根实体索引的一部分进行索引。如果您希望根据相关对象的属性搜索给定实体,这很有用。目标是返回相关城市为 Atlanta 的位置(在 Lucene 查询解析器语言中,语言将转换为 address.city:Atlanta)。位置字段将在位置索引中 索引。Place 索引文档还将包含您可以 查询的 address.id、address . 字段。
street 和 address.city
示例:索引关联
由于在使用 @IndexedEmbedded 技术时,Lucene 索引中数据已被非常规化,因此 Hibernate Search 必须了解 Place 对象中的任何变化,以及 Address 对象中的任何更改,以便索引保持最新。为确保在地址发生更改时 Lucene 文档得到更新,请使用 @ContainedIn 标记双向关系的另一侧。
@ContainedIn 对于指向实体的关联和嵌入式(收集)对象的关联都很有用。
若要对此展开,以下示例演示了嵌套 @IndexedEmbedded :
示例:@IndexedEmbedded 和 @ContainedIn 的嵌套使用
任何 @*ToMany、@*ToOne 和 @Embedded 属性都可以标上 @IndexedEmbedded。然后,关联的类的属性将添加到主实体索引中。索引将包含以下字段:
- id
- name
- address.street
- address.city
- address.ownedBy_name
默认前缀是 propertyName.,遵循传统的对象导航约定。您可以使用 prefix 属性覆盖它,如 ownedBy 属性中所示。
前缀不能设置为空字符串。
当对象图包含类(而非实例)的循环依赖项时,需要 深度 属性。例如,如果所有者指向位置:Hibernate 搜索将在到达预期深度(或到达对象图形边界)后停止包含索引的嵌入式属性。具有自引用的类是 cyclic 依赖项示例。在我们的示例中,由于 深度 设置为 1,Owner 中的任何 @IndexedEmbedded 属性都将被忽略。
使用 @IndexedEmbedded 作为对象关联可让您表达查询(使用 Lucene 的查询语法),例如:
返回名称包含 JBoss 以及地址城市为 Atlanta 的位置。在 Lucene 查询中,这是:
+name:jboss +address.city:atlanta
+name:jboss +address.city:atlantaCopy to Clipboard Copied! Toggle word wrap Toggle overflow 返回名称包含 JBoss 的位置,以及所有者名称包含 Joe 的位置。在 Lucene 查询中,该选项为
+name:jboss +address.ownedBy_name:joe
+name:jboss +address.ownedBy_name:joeCopy to Clipboard Copied! Toggle word wrap Toggle overflow
此行为以更有效的方式(降低数据重复的成本)模仿关系连接操作。请记住,开箱即用时 Lucene 索引没有任何关联概念,连接操作也不存在。这有助于保持关系模式规范化,同时从完整的文本索引速度和特性丰富的中受益。
关联的对象本身(但不必)为 @Indexed
当 @IndexedEmbedded 指向某一实体时,其关联必须是方向的,并且必须给另一方添加注释 @ContainedIn (如上例中所示)。如果没有,Hibernate Search 将无法在相关实体更新时更新根索引(在本示例中,相关地址实例更新时必须更新 Place 索引文档)。
有时,由 @IndexedEmbedded 标注的对象类型并非 Hibernate 和 Hibernate Search 所针对的对象类型。当接口用于代替其实施时,尤其会出现这种情况。因此,您可以使用 targetElement 参数覆盖 Hibernate Search 所针对的对象类型。
示例:使用 @IndexedEmbedded targetElement 属性
7.4.1.8. 将对象嵌入式限制为特定路径 复制链接链接已复制到粘贴板!
@IndexedEmbedded 注释也提供 includePaths 属性,可用于作为深度的替代方案或与其组合。
仅使用深度时,会在同一深度以递归方式添加嵌入式类型的所有索引字段。这样更加难以仅选择特定路径而不添加所有其他字段,而可能不需要这些字段。
为避免不必要的加载和索引实体,您可以精确指定所需的路径。典型的应用程序可能需要不同路径的不同深度,或者换句话说可能需要明确指定路径,如下例所示:
示例:使用 @IndexedEmbedded 的 includePaths 属性
使用上例中所示的映射,您可以按 名称和 /或 姓氏 搜索 Person,以及/或父 名称。它不会索引父名称 的姓氏,因此无法对父名进行搜索,但会加快索引、节省空间并提高整体性能。
@IndexedEmbeddedincludePaths 除常规地为深度指定有限值 的索引外,还包括指定的路径。使用 includePaths 并保留深度未定义时,行为等同于设置 depth=0:只有包含的路径才会被索引。
示例:使用 @IndexedEmbedded 的 includePaths 属性
在上面的示例中,每个人都将拥有其名称和姓氏属性索引。父项的名称和姓氏也将进行索引,其中最多可递归为第二行,因为存在depth 属性。可以按姓名或姓氏直接搜索该人员、其父项或父项。除第二个级别外,我们还会再为一个级别编制索引,而仅索引名称,而非姓氏。
这会在索引中生成以下字段:
-
ID:作为主密钥 -
_hibernate_class:存储实体类型 -
名称:作为直接字段 -
Surname:作为直接字段 -
parent.name:作为嵌入式字段(深度 1) -
parent.surname:作为嵌入式字段,在深度 1 中 -
parent.parents.name:作为嵌入式字段,位于深度 2 -
parent.parents.surname:作为嵌入式字段,显示深度 2 -
parent.parents.parents.name:作为 includePaths 指定的额外路径。第一个父级.从字段名称中推断,剩余的路径是 includePaths 的属性。
如果您要首先定义所需的查询(如此时您准确知道需要哪些字段)以及不需要哪些其他字段来实施您的用例,那么明确控制索引路径可能会更加简单。
7.4.2. boosting 复制链接链接已复制到粘贴板!
Lucene 具有 增强 概念,使您可以提供某些文档或字段的重要性比其他文档或字段多或更低。Lucene 区分索引和搜索时间提升。以下小节介绍了如何使用 Hibernate Search 实现索引时间提升。
7.4.2.1. 静态索引时间嵌套 复制链接链接已复制到粘贴板!
若要为索引化的类或属性定义静态提升值,您可以使用 @Boost 注释。您可以在 @Field 内使用此注释,或者直接在方法或类级别上指定。
示例:使用 @Boost 的不同方式
在上面的示例中,Essay 达到搜索列表顶部的可能性将乘以 1.7。summary 字段将为 3.0(2 * 1.5),因为属性上的 @Field.boost 和 @Boost 是累加的,比 isbn 字段更重要。文本字段将比 isbn 字段更重要 1.2 倍。请注意,该解释最严格无误,但对于所有实际用途而言,它非常简单,非常接近现实。
7.4.2.2. 动态索引时间嵌套 复制链接链接已复制到粘贴板!
Static Index Time Boosting 中使用的 @Boost 注释定义一个静态提升因子,它独立于运行时索引的实体的状态。然而,在有些用例中,增速因素可能取决于实体的实际状态。在这种情况下,您可以使用 @DynamicBoost 注释和附带的自定义 BoostStrategy。
示例:Dynamic Boost
在上例中,在将 VIPBoostStrategy 指定为要在索引时使用的 BoostStrategy 接口的实现的类级别上定义动态提升。您可以将 @DynamicBoost 放置在类或字段级别上。根据注释的放置,整个实体都传递到 defineBoost 方法,或者仅传递注解的字段/质量值。您要将传递的对象投给正确的类型。在示例中,VIP 人员的所有索引值都将与普通人的值加倍。
指定的 BoostStrategy 实现必须定义一个公共的 no-arg 构造器。
当然,您可以在实体中混合和匹配 @Boost 和 @DynamicBoost 注释。所有定义的增压因素都是累计的。
7.4.3. 分析 复制链接链接已复制到粘贴板!
分析 是将文本转换为单个术语(词)的过程,可以视为全文本搜索引擎的主要功能之一。Lucene 利用分析器的概念来控制此过程。在下一节中,我们将介绍 Hibernate 搜索提供的多种方式来配置分析器。
7.4.3.1. 类的默认 Analyzer 和 Analyzer 复制链接链接已复制到粘贴板!
用于索引令牌字段的默认分析器类可通过 hibernate.search.analyzer 属性进行配置。此属性的默认值为 org.apache.lucene.analysis.standard.StandardAnalyzer。
您还可以为每个实体定义分析器类、属性甚至每个 @Field(在一个属性中索引多个字段时很有用)。
示例:使用 @Analyzer 的不同方式
在本例中,EnityAnalyzer 用于索引令牌化属性(名称),但 摘要 和 正文 除外,它们分别使用 propertiesAnalyzer 和 FieldAnalyzer 索引。
在同一个实体中混合不同的分析器大部分时候是不良做法。它使查询构建更复杂,结果更难以预测(对于 novice),尤其是如果您使用 QueryParser(对整个查询使用同一个分析器)。作为经验法,对于任何给定字段,应将同一分析器用于索引和查询。
7.4.3.2. 命名分析器 复制链接链接已复制到粘贴板!
分析器可能会变得非常复杂。因此,增加了 Hibernate 搜索分析器定义的概念。分析器定义可以被许多 @Analyzer 声明重复使用,其包含:
- name: 用于引用定义的唯一字符串
- char 过滤器列表: 每个 char 过滤器负责在令牌化之前预先处理输入字符。Char 过滤器可以添加、更改或删除字符;一个常用的用法是字符规范化
- 令牌器: 负责将输入流令牌到单个单词
- 过滤器列表: 每个过滤器负责删除、修改或有时在 tokenizer 提供的流中添加词语
这种任务分离(一个 char 过滤器列表和一个跟一个过滤器列表)可轻松重复利用各个组件,并让您以非常灵活的方式(如 Lego)构建自定义分析器。通常而言,Car 过滤器在字符输入中执行一些预处理,然后令牌程序通过将字符输入转换为令牌来启动令牌化过程,然后由 TokenFilters 进一步处理。Hibernate Search 利用 Solr 分析器框架来支持此基础架构。
让我们回顾一下下面描述的一个具体示例。首先,一个 char 过滤器由工厂定义。在我们的示例中,使用了映射 char 过滤器,并将根据映射文件中指定的规则替换输入中的字符。接下来定义了令牌程序。这个示例使用标准令牌程序。最后但并非最不重要的是,一个过滤器列表由其工厂定义。在我们的示例中,StopFilter 过滤器构建为读取专用的词语属性文件。过滤器还应忽略大小写。
示例:@AnalyzerDef 和 Solr Framework
过滤器和 char 过滤器按照 @AnalyzerDef 注释中定义的顺序应用。订单很重要!
某些令牌程序、令牌过滤器或 char 过滤器会加载资源,如配置或元数据文件。stop 过滤器和同义词过滤器就是这种情况。如果资源 charset 没有使用虚拟机默认值,您可以通过添加 resource_charset 参数来显式指定它。
示例:使用特定 Charset 加载属性文件
定义之后,分析器定义就可通过 @Analyzer 声明重复利用,如下例中所示:
示例:按名称引用分析器
@AnalyzerDef 声明的 AnalyzerDef 实例通过其名称在 SearchFactory 中也可用,该名称在构建查询时非常有用。
Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("customanalyzer");
Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("customanalyzer");
查询中的字段必须使用用于索引字段的同一分析器进行分析,以便它们使用共同"语言":在查询和索引过程之间重复利用相同的令牌。该规则有一些例外情况,但大部分时候确实如此。尊重它,除非您知道自己正在做什么。
7.4.3.3. 可用分析器 复制链接链接已复制到粘贴板!
SOLR 和 Lucene 附带许多有用的默认 char 过滤器、令牌程序和过滤器。您可以在 http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters 找到 char 过滤器工厂、令牌方工厂和过滤工厂的完整列表。我们来看一下其中几个。
| 工厂 | 描述 | 参数 |
|---|---|---|
| MappingCharFilterFactory | 根据资源文件中指定的映射,将一个或多个字符替换为一个或多个字符 |
|
| HTMLStripCharFilterFactory | 删除 HTML 标准标签,保留文本 | none |
| 工厂 | 描述 | 参数 |
|---|---|---|
| StandardTokenizerFactory | 使用 Lucene StandardTokenizer | none |
| HTMLStripCharFilterFactory | 删除 HTML 标签,保留文本并将其传递到标准Tokenizer。 | none |
| PatternTokenizerFactory | 将文本拆分到指定的正则表达式模式. | pattern :用于令牌化的正则表达式 Group :表示要提取到令牌中的哪个模式组 |
| 工厂 | 描述 | 参数 |
|---|---|---|
| StandardFilterFactory | 从单词中删除缩写和 的点数 | none |
| LowerCaseFilterFactory | 小写所有单词 | none |
| StopFilterFactory | 删除与 stop 词语列表匹配的词语(令牌) | word: 指向包含 stop 词语的资源文件 ignoreCase: true,如果比较 stop 字时应忽略大小写,否则为 false |
| SnowballPorterFilterFactory | 以给定语言将单词减到其 root。(例如:保护、保护、保护共享同一根)。使用这样的过滤器可以搜索匹配相关的词语。 |
|
我们建议检查 IDE 中 org.apache.lucene.analysis.TokenizerFactory 和 org.apache.lucene.analysis.TokenFilterFactory 中的所有实施,以查看可用的实施。
7.4.3.4. 动态分析器选择 复制链接链接已复制到粘贴板!
目前,所有介绍的指定分析器的方法都是静态的。然而,在某些用例中,根据要索引的实体的当前状态(例如在多语言应用程序中)来选择分析器很有用。例如,对于 BlogEntry 类,分析器可能依赖于条目的语言属性。根据此属性,应当选择正确的语言特定语言来索引实际文本。
要启用此动态分析器选择 Hibernate Search,请引入 AnalyzerDiscriminator 注释。以下示例演示了此注解的用法。
示例:@AnalyzerDiscriminator 的使用
使用 @AnalyzerDiscriminator 的先决条件是,将要动态使用的所有分析器都通过 @AnalyzerDef 定义预定义。如果出现这种情况,可以将 @AnalyzerDiscriminator 注释放在该类或动态选择分析器的实体的特定属性上。通过 AnalyzerDiscriminator 的 impl 参数,您可以指定特定的 Discriminator 接口实施。您要为此接口提供一个实施。您唯一需要实施的方法是 getAnalyzerDefinitionName(),它为添加到 Lucene 文档中的每个字段调用。索引化的实体也传递到 interface 方法。只有在将 AnalyzerDiscriminator 放置到属性级别而不是类级别时,才会设置 value 参数。在本例中,值表示此属性的当前值。
如果不应覆盖默认分析器,则 Discriminator 接口的实施必须返回现有分析器定义的名称或 null。上面的示例假定语言参数为 'de' 或 'en',它与 @AnalyzerDefs 中的 指定名称匹配。
7.4.3.5. 检索分析器 复制链接链接已复制到粘贴板!
当在域模型中使用了多个分析器时,可以检索分析器,以便从医疗或手机近似中受益。在这种情况下,使用相同的分析器来构建查询。或者,使用 Hibernate Search 查询 DSL,它会自动选择正确的分析器。请查看
无论您是使用 Lucene 编程 API,还是 Lucene 查询解析器,您都可以检索给定实体的范围分析器。有作用域分析器是一个分析器,它根据字段索引来应用正确的分析器。请记住,可以在给定实体上定义多个分析器,每个实体都在单个字段上工作。一个作用域分析器可将所有这些分析器统一到上下文感知分析器中。尽管该理论似乎比较复杂,但在查询中使用正确的分析器非常简单。
当您对子实体使用编程映射时,只能查看子实体定义的字段。从父实体继承的字段或方法(使用 @MappedSuperclass 标注)不可配置。要配置从父实体继承的属性,可覆盖子实体中的 属性,或者为父实体创建编程映射。这模拟了注解的使用,除非子实体中重新定义了父实体的字段或方法。
示例:构建全文本查询时使用 Scoped Analyzer
在上例中,歌曲标题按照两个字段索引:标准分析器在字段 标题中 使用,greject _stemmed 字段中则使用一个适当的 分析器。通过使用搜索工厂提供的分析器,查询会根据目标字段使用适当的分析器。
您还可以使用 searchFactory.getAnalyzer(String)根据定义名称检索 @Analyzer Def 定义的分析器。
7.4.4. 网桥 复制链接链接已复制到粘贴板!
在讨论实体的基本映射时,到目前为止一个重要的事实被忽略。在 Lucene 中,所有索引字段都必须以字符串表示。标有 @Field 的所有实体 属性都必须转换为要索引的字符串。我们目前尚未提到过的原因是,对于您的大多数属性,Hibernate Search 为您承担了转换任务,得益于一组内置桥。然而,在某些情况下,您需要更精细地控制转换过程。
7.4.4.1. 内置网桥 复制链接链接已复制到粘贴板!
Hibernate Search 附带一组 Java 属性类型和完整文本表示法之间的内置桥接。
- null
-
每个默认
null元素都没有索引。Lucene 不支持 null 元素。但在某些情况下,插入代表空值的自定义令牌会很有用。如需更多信息,请参阅。 - java.lang.String
- 字符串的索引方式是短、短、整数、Integer、长、Long、float、Float、双.
- Double, BigInteger, BigDecimal
数字转换为字符串表示法。请注意,数字不能由 Lucene(即在范围查询中使用)从开箱即用:它们必须被 padded。
注意使用 Range 查询存在缺点,另一种方法是使用 Filter 查询,它将结果查询过滤到适当的范围。Hibernate Search 还支持使用自定义 StringBridge,如 自定义网桥 中所述。
- java.util.Date
日期存储为 yyyMMddHHmmsSSS,时间为 yyyMMddHHmmsSSS,时间为 2006 年 11 月 7 日 4:03PM 和 12ms EST。您不应该真正对内部格式造成干扰。重要的是,在使用 TermRangeQuery 时,您应该知道日期必须以 GMT 时间表示。
通常,不需要存储毫秒的最新数据。
@DateBridge定义您希望在索引中存储的适当解析(@DateBridge(resolution=Resolution.DAY)。然后,将相应地截断日期模式。
解析低于 MILLISECOND 的日期不能是 @DocumentId。
默认日期网桥使用 Lucene 的 DateTools 从和转换为 String。这意味着所有日期都以 GMT 时间表示。如果您的要求要在固定的时区中存储日期,您必须实施自定义日期桥接。确保您了解应用程序与日期索引和搜索相关的要求。
- java.net.URI, java.net.URL
- URI 和 URL 将转换为其字符串表示法。
- java.lang.Class
- class 将转换为其完全限定类名称。重新验证类时,使用线程上下文类加载程序。
7.4.4.2. 自定义网桥 复制链接链接已复制到粘贴板!
有时,Hibernate Search 的内置网桥不涵盖某些属性类型,或者网桥使用的字符串表示不满足您的要求。以下段落描述了此问题的几种解决方案。
7.4.4.2.1. StringBridge 复制链接链接已复制到粘贴板!
最简单的自定义解决方案是让 Hibernate 搜索您的预期对象实施到 String 网桥。为此,您需要实施 org.hibernate.search.bridge.StringBridge 接口。所有实施都必须是并发使用线程安全。
示例:自定义字符串实现
根据上例中定义的字符串网桥,任何属性或字段都可通过 @FieldBridge 注释来使用此网桥:
@FieldBridge(impl = PaddedIntegerBridge.class) private Integer length;
@FieldBridge(impl = PaddedIntegerBridge.class)
private Integer length;
7.4.4.2.2. 参数网桥 复制链接链接已复制到粘贴板!
参数也可以传递到网桥实施,使其更灵活。下例实施参数化Bridge 接口和参数通过 @FieldBridge 注释传递:
示例:将参数传递给网桥实施
ParameterizedBridge 接口可通过TwoWayString 实施来实现。
Bridge 和 BridgeFieldBridge 实现 String
所有实施都必须是线程安全,但参数在初始化过程中设置,此阶段不需要特别注意。
7.4.4.2.3. 类型 Aware Bridge 复制链接链接已复制到粘贴板!
有时对于获得应用桥接的类型很有用:
- 字段/工具级网桥的属性的返回类型。
- 类级网桥的类类型。
例如,一个网桥,它以自定义的方式处理枚举,但需要访问实际的枚举类型。实现 AppliedOnTypeAwareBridge 的任何网桥都会获得注入时应用桥接的类型。与参数一样,注入的类型无需特别注意线程安全。
7.4.4.2.4. 双Way Bridge 复制链接链接已复制到粘贴板!
如果您希望在 id 属性(即带有 @DocumentId 注释)上使用网桥实施,您需要使用名为 TwoWayString Bridge 的 String Bridge 版本。Hibernate Search 需要读取标识符的字符串表示,并从中生成对象。使用 @FieldBridge 注释的方式没有区别。
示例:实施双WayStringBridge Usable for id Properties
双向过程务必要具有幂等性(即,object = stringToObject(objectToString(对象))。
7.4.4.2.5. FieldBridge 复制链接链接已复制到粘贴板!
当将属性映射到 Lucene 索引时,有些用例需要不仅仅是简单的对象来字符串转换。为为您提供最大灵活性,您还可以将桥实施为 FieldBridge。此界面为您提供一个属性值,并允许您在 Lucene Document 中按照您想要的方式对其进行映射。例如,您可以在两个不同的文档字段中存储属性。接口的概念与 Hibernate 用户类型非常相似。
示例:实施 FieldBridge Interface
在上面的示例中,这些字段不会直接添加到 Document 中。相反,添加被委派给 LuceneOptions 帮助程序;此帮助程序将应用您在 @Field( 如 Store 或 TermVector )上选择的选项,或应用所选的 @Boost 值。封装 COMPRESS 实施的复杂性特别有用。尽管建议将任何字段委派给 LuceneOptions 以向文档添加字段,但不会阻止您直接编辑文档,并在您需要时忽略 LuceneOptions。
创建类似 LuceneOptions 的类,以方便您的应用程序免受 Lucene API 的变化,并简化您的代码。如果您愿意,请使用它们,但如果您需要更大的灵活性,则不需要.
7.4.4.2.6. ClassBridge 复制链接链接已复制到粘贴板!
有时,组合给定实体的多个属性并以特定的方式将此组合索引到 Lucene 索引中很有用。@ClassBridge 和 @ClassBridges 注释可以在类级别上定义,而非属性级别。在本例中,自定义字段网桥实施接收实体实例作为 value 参数,而不是特定属性。虽然如下例中未显示,但 @ClassBridge 支持 Basic Mapping 部分中讨论的 termVector 属性。
示例:实施类桥接
在本例中,特定的 CatFieldsClassBridge 应用到 部门 实例,字段桥接随后串联分支和网络,并索引串联。