索引定义

搜索的索引是通过 Java 接口定义的,接口中描述哪些实体以及哪些属性需要建立索引。需要为每一个启用全文搜索的实体创建此类接口。

索引定义接口

索引定义的 Java 接口需要满足下列条件:

  • 命名无限制。

  • 需要使用 @JmixEntitySearchIndex 注解。

  • 注解必须有 entity 参数,定义此接口服务的实体。每个可搜索的实体对应一个索引定义接口。

@JmixEntitySearchIndex(entity = Order.class)
public interface OrderIndexDefinition {

}

实体属性索引通过接口的方法定义。方法需要满足下列条件:

  • 必须返回 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 中定义的分析器(Analyzer)名称,用在索引字段映射中。如果未指定,则使用 ES 的 默认分析器

  • indexFileContent - 定义是否对文件属性的文件内容建立索引。默认 true

includePropertiesexcludeProperties 都支持 * 通配符。该通配符将转换为相应级别的本地属性:

  • * - 索引实体的本地属性。

  • refField.* - refField 属性指定的关联实体的本地属性。

通配符不覆盖反向引用属性和实体 特性 属性:versioncreatedBy 等。

仅当 includeProperties 包含通配符时,使用 excludeProperties 比较方便,用于限制属性范围。示例:

@AutoMappedField(
        includeProperties = {"*", "customer.*"},
        excludeProperties = {"number", "customer.firstName"})
void orderCustomerMapping();

分析器以不同的方式转换输入文本值,包括对某些语言词法的解析。指定的分析器用于索引和搜索步骤。

@JmixEntitySearchIndex(entity = Customer.class)
public interface CustomerIndexDefinition {

    @AutoMappedField(
            includeProperties = {"firstName", "lastName"},
            analyzer = "russian")
    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 类型的属性,也是最常见的情况,属性值用作索引值。ES 中的索引字段类似这样:

"textualFieldName": "value"

如果有多个值:

"textualFieldName": ["value1", "value2"]

引用实体

这是关联实体的引用。只有关联实体的实例名用作索引值,不包含关联实体的任何内部属性。如需对关联实体的内部属性建立索引,需要显式添加 refProperty.nestedPropertyrefProperty.*

ES 中的索引字段类似这样:

"refFieldName": {
  "_instance_name": "instanceNameValue"
}

如果有多个值:

"refFieldName": {
  "_instance_name": ["instanceNameValue1", "instanceNameValue2"]
}

文件类型

这是 FileRef 类型的属性,引用 文件存储 中的文件。文件名和文件内容默认都会用作索引值。如果仅需对文件名建立索引,需要设置 @AutoMappedFieldindexFileContent 参数为 false

@AutoMappedField(
        includeProperties = {"*"},
        indexFileContent = false)
void fileMapping();

ES 中的索引字段类似这样:

"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"
	}
]

枚举类型

对于 枚举类型 属性,会使用其全部语言环境的 本地化值 作为索引值。

ES 中的索引字段类似这样:

"enumFieldName": ["enValue", "ruValue"]

如果有多个值,则会展示所有值的所有语言本地化值:

"enumFieldName": ["enValue1", "ruValue1", "enValue2", "ruValue2"]

嵌入实体

这是内部 JPA 实体的引用。包含一个嵌入实体属性与包含该实体所有内部属性("someEmbeddedProperty" = "someEmbeddedProperty.*")一致。索引值根据内部属性的不同类型构建,会忽略不支持的类型。

假设一个根实体的 customer 属性关联至内部的 Customer 实体(具有 firstNamelastName 属性)。如果在映射中包含了 customer 属性,则会导致间接包含 customer.firstNamecustomer.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 类型的属性。
只能有一个编程式映射的方法。如果存在此方法,则会忽略所有的映射注解。