索引定义
搜索的索引是通过 Java 接口定义的,接口中描述哪些实体以及哪些属性需要建立索引。建议为所有需要使用全文搜索的实体创建此类接口。
索引定义接口
索引定义的 Java 接口需要满足下列条件:
-
命名无限制。
-
必须使用
@JmixEntitySearchIndex
注解。
@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {
}
@JmixEntitySearchIndex
属性:
-
entity
- 必需属性。指定该索引定义关联的实体类。 -
indexName
- 可选属性。指定实体索引的全名。如果没设置,则索引名依据 前缀和实体名 生成。
实体属性索引通过接口的方法定义。方法需要满足下列条件:
-
必须返回
void
。 -
命名无限制。
-
无参数。
-
无具体实现。
-
需要使用
@AutoMappedField
注解。
@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {
@AutoMappedField(includeProperties =
{"number", "product", "customer.status", "customer.lastName"})
void orderMapping();
}
AutoMappedField 注解
@AutoMappedField
注解支持将实体属性根据其类型映射为 ES 索引(参见 下文)。该注解有下列参数:
-
includeProperties
- 应该建立索引的实体属性列表。支持使用点标记指定关联实体的属性。默认不包含任何属性,即不建立任何属性的索引。 -
excludeProperties
- 不需要建立索引的实体属性列表。支持使用点标记指定关联实体的属性。默认不包含任何属性。 -
analyzer
- ES/OpenSearch 中定义的分析器(Analyzer)名称,用在索引字段映射中。如果未指定,则使用standard
分析器。 -
indexFileContent
- 定义是否对文件属性的文件内容建立索引。默认true
。
includeProperties
和 excludeProperties
都支持 *
通配符。该通配符将转换为相应级别的本地属性:
-
*
- 索引实体的本地属性。 -
refField.*
-refField
属性指定的关联实体的本地属性。
通配符不覆盖反向引用属性和实体 特性 属性:version
、createdBy
等。
仅当 includeProperties
包含通配符时,使用 excludeProperties
比较方便,用于限制属性范围。示例:
@AutoMappedField(
includeProperties = {"*", "customer.*"},
excludeProperties = {"number", "customer.firstName"})
void orderCustomerMapping();
分析器以不同的方式转换输入文本值,包括对某些语言词法的解析。指定的分析器用于索引和搜索步骤。
@JmixEntitySearchIndex(entity = Customer.class)
public interface CustomerIndexDefinition {
@AutoMappedField(
includeProperties = {"firstName", "lastName"},
analyzer = "german")
void customerMapping();
}
可以在单个方法上使用多个映射注解,也可以在多个方法之间拆分以定义不同的分组。以下示例都表示同一个定义:
@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {
@AutoMappedField(includeProperties =
{"number", "product", "customer.status", "customer.lastName"})
void orderMapping();
}
@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {
@AutoMappedField(includeProperties = {"number", "product"})
@AutoMappedField(includeProperties = {"customer.status", "customer.lastName"})
void orderMapping();
}
@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {
@AutoMappedField(includeProperties = {"number", "product"})
void orderMapping();
@AutoMappedField(includeProperties = {"customer.status", "customer.lastName"})
void customerMapping();
}
自动映射
@AutoMappedField
注解的自动映射支持下列类型的实体属性:
通配符能覆盖所有这些属性。
文本属性
String
类型的属性是最常见的情况,属性值即用作索引值。
索引字段类似这样:
"textualFieldName": "value"
如果有多个值:
"textualFieldName": ["value1", "value2"]
引用属性
这类属性是关联实体的引用。只有关联实体的实例名用作索引值,不包含关联实体的任何内部属性。如需对关联实体的内部属性建立索引,需要在映射中显式添加 refProperty.nestedProperty
或 refProperty.*
。
索引字段类似这样:
"refFieldName": {
"_instance_name": "instanceNameValue"
}
如果有多个值:
"refFieldName": {
"_instance_name": ["instanceNameValue1", "instanceNameValue2"]
}
文件属性
这是 FileRef
类型的属性,指向 文件存储 中的文件。文件名和文件内容默认都会用作索引值。如果仅需对文件名建立索引,需要设置 @AutoMappedField
的 indexFileContent
参数为 false
:
@AutoMappedField(
includeProperties = {"*"},
indexFileContent = false)
void fileMapping();
索引字段类似这样:
"fileRefField": {
"_file_name" : "File name",
"_content" : "File content if enabled"
}
如果有多个值:
"fileRefField": [
{
"_file_name" : "File name 1",
"_content" : "File content 1"
},
{
"_file_name" : "File name 2",
"_content" : "File content 2"
}
]
枚举属性
索引字段类似这样:
"enumFieldName": ["enValue", "ruValue"]
如果属性包含有多个枚举值,则会展示所有值的所有语言本地化值:
"enumFieldName": ["enValue1", "ruValue1", "enValue2", "ruValue2"]
嵌入实体属性
这是内部 JPA 实体的引用。添加一个嵌入实体属性也就是包含其所有内部属性("someEmbeddedProperty" = "someEmbeddedProperty.*")。索引值根据内部属性的不同类型构建,会忽略不支持的类型。
假设一个根实体的 customer
属性关联至内部的 Customer
实体(具有 firstName
和 lastName
属性)。如果在映射中包含了 customer
属性,则会自动包含 customer.firstName
和 customer.lastName
属性。
内部属性和集合
内部嵌套属性可用点标记指定:refProperty.nestedRefProperty.targetDataProperty
。
此外,系统也支持集合属性,可以包含不同级别的内部集合属性。此时索引会存储最低一级属性的全部值。例如,collectionOfReferences.nestedCollectionOfAnotherReferences.name
保存如下:
"collectionOfEntityA": {
"nestedCollectionOfEntityB": {
"name": ["value1", ..., "valueN"]
}
}
数组包含根实体中全部 EntityA
实例的全部 EntityB
实例的 name
属性值。
编程式映射
除了使用注解之外,还可以通过编程的方式构建映射定义。
需要在索引定义接口中创建满足下列条件的方法:
-
是 default 方法。
-
命名无限制。
-
为了自定义配置,可以使用 Spring bean 作为参数。
-
必须返回
MappingDefinition
类型。 -
必须使用
@ManualMappingDefinition
注解。
方法体中,可以使用 MappingDefinition.builder()
创建映射定义。
@JmixEntitySearchIndex(entity = Customer.class)
public interface CustomerIndexDefinition {
@ManualMappingDefinition (1)
default MappingDefinition mapping(FilePropertyValueExtractor filePropertyValueExtractor) { (2)
return MappingDefinition.builder()
.addElement(
MappingDefinitionElement.builder()
.includeProperties("*") (3)
.excludeProperties("hobby", "maritalStatus") (4)
.withFieldMappingStrategyClass(AutoMappingStrategy.class) (5)
.withPropertyValueExtractor(filePropertyValueExtractor) (6)
.build()
)
.build();
}
}
1 | @ManualMappingDefinition 注解标记的方法使用了手动创建映射定义。 |
2 | 为了自定义映射配置,可以传入 Spring bean 作为参数。 |
3 | 需要建立索引的属性列表。这里使用 * 通配符包含 Customer 实体的所有本地属性。 |
4 | 不需要建立索引的属性列表。 |
5 | 需要用 FieldMappingStrategy 的实现类做属性映射。映射策略也可以定义为类的实例,需要用 withFieldMappingStrategy() 方法设置,参数为映射策略的实例。 |
6 | 显式指定属性值解析器。例如,FilePropertyValueExtractor 可用于处理 FileRef 类型的属性。 |
只能有一个编程式映射的方法。如果存在此方法,则会忽略所有的映射注解。 |
可索引谓词
建立索引的过程中,可以使用额外的实体级别的条件。 条件是通过配置可索引谓词(Indexable Predicate)进行添加。在建立索引的过程中,这个谓词会在每个实体实例上做检查,判断实例是否能加入索引。
谓词不会在删除时使用。
如需配置可索引谓词,请添加满足下列条件的方法:
-
是 default 方法
-
命名无限制。
-
返回类型为
Predicate<TargetEntity>
,这里 'TargetEntity' 是当前注解中entity()
参数的值。 -
谓词逻辑需要的 Spring bean 可以作为参数。
-
带
@IndexablePredicate
注解。
在方法体中创建实际的谓词并作为结果返回。
传递给谓词的实体实例仅包含声明用于索引的属性,其他属性均未定义。如需访问其他属性,需要在谓词中用合适的 fetch plan 重新加载。 |
@JmixEntitySearchIndex(entity = Customer.class)
public interface CustomerIndexDefinition {
@AutoMappedField(
includeProperties = {"firstName", "lastName"},
analyzer = "german")
void customerMapping();
@IndexablePredicate
default Predicate<Customer> indexCustomerWithGoldStatusOnlyPredicate(DataManager dataManager) {
return (instance) -> {
Id<Customer> id = Id.of(instance);
Customer reloadedInstance = dataManager.load(id)
.fetchPlanProperties("status")
.one();
Status status = reloadedInstance.getStatus();
return Status.GOLD.equals(status);
};
}
}