Jkes简介
Jkes是一个基于Java、Kafka和ElasticSearch的强大搜索框架。它为开发人员提供了一种简单而强大的方式来实现搜索功能,大大简化了搜索相关的开发工作。Jkes的核心设计理念是通过注解驱动的方式实现对象/文档映射,并提供RESTful风格的搜索API,让开发人员能够专注于业务逻辑的实现,而不必过多关注搜索的底层实现细节。
主要特性
Jkes框架具有以下主要特性:
- 注解驱动的JPA风格对象/文档映射
- 基于REST API的文档搜索
- 与Spring Data JPA无缝集成
- 自动索引管理和文档同步
- 多租户支持
- 灵活的配置选项
这些特性使Jkes成为一个功能全面、易于使用的搜索解决方案,适合各种规模的项目使用。
安装和配置
要开始使用Jkes,首先需要进行安装和基本配置。以下是具体步骤:
1. 安装依赖组件
Jkes依赖于以下组件:
- Kafka和Kafka Connect
- ElasticSearch
- Smart Chinese Analysis Plugin (ElasticSearch插件)
确保这些组件已正确安装和配置。
2. 添加Maven依赖
在项目的pom.xml文件中添加Jkes的依赖:
<dependency>
<groupId>com.timeyang</groupId>
<artifactId>jkes-spring-data-jpa</artifactId>
<version>1.1.0</version>
</dependency>
3. 配置Jkes
创建一个配置类,启用Jkes相关功能:
@EnableAspectJAutoProxy
@EnableJkes
@Configuration
public class JkesConfig {
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory factory, EventSupport eventSupport) {
return new SearchPlatformTransactionManager(new JpaTransactionManager(factory), eventSupport);
}
}
4. 提供JkesProperties
创建一个JkesProperties的实现类,提供必要的配置信息:
@Component
@Configuration
public class JkesConf extends DefaultJkesPropertiesImpl {
@PostConstruct
public void setUp() {
Config.setJkesProperties(this);
}
@Override
public String getKafkaBootstrapServers() {
return "kafka1:9092,kafka2:9092,kafka3:9092";
}
@Override
public String getKafkaConnectServers() {
return "http://connect1:8083,http://connect2:8083";
}
@Override
public String getEsBootstrapServers() {
return "http://es1:9200,http://es2:9200,http://es3:9200";
}
@Override
public String getDocumentBasePackage() {
return "com.example.domain";
}
@Override
public String getClientId() {
return "my_app";
}
}
5. 添加索引管理端点
为了方便管理索引,可以添加一个索引管理的REST控制器:
@RestController
@RequestMapping("/api/search")
public class SearchEndpoint {
private final Indexer indexer;
@Autowired
public SearchEndpoint(Indexer indexer) {
this.indexer = indexer;
}
@PostMapping("/start_all")
public void startAll() {
indexer.startAll();
}
@PostMapping("/start/{entityClassName}")
public void start(@PathVariable("entityClassName") String entityClassName) {
indexer.start(entityClassName);
}
@PutMapping("/stop_all")
public Map<String, Boolean> stopAll() {
return indexer.stopAll();
}
@PutMapping("/stop/{entityClassName}")
public Boolean stop(@PathVariable("entityClassName") String entityClassName) {
return indexer.stop(entityClassName);
}
@GetMapping("/progress")
public Map<String, IndexProgress> getProgress() {
return indexer.getProgress();
}
}
完成以上配置后,Jkes就可以在项目中使用了。
使用Jkes
定义文档实体
使用Jkes的第一步是定义文档实体。Jkes使用注解来标记需要索引的实体类和字段。以下是一个示例:
@Data
@Entity
@Document
public class Person extends AuditedEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@MultiFields(
mainField = @Field(type = FieldType.Text),
otherFields = {
@InnerField(suffix = "raw", type = FieldType.Keyword),
@InnerField(suffix = "english", type = FieldType.Text, analyzer = "english")
}
)
private String name;
@Field(type = FieldType.Keyword)
private String gender;
@Field(type = FieldType.Integer)
private Integer age;
private String description;
@Field(type = FieldType.Object)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "group_id")
private PersonGroup personGroup;
}
在这个例子中:
@Document
注解标记这个类为一个需要索引的文档实体。@Field
注解用于指定字段的索引类型。@MultiFields
注解允许为一个字段创建多个索引,以支持不同的查询需求。
自动索引
当使用标准的JPA操作(如save、delete等)对实体进行操作时,Jkes会自动处理索引的更新。例如:
@Service
public class PersonService {
@Autowired
private PersonRepository personRepository;
@Transactional
public Person createPerson(Person person) {
return personRepository.save(person);
}
@Transactional
public void deletePerson(Long id) {
personRepository.deleteById(id);
}
}
在这个服务类中,当调用createPerson
方法时,Jkes会自动将新创建的Person对象索引到ElasticSearch中。同样,当调用deletePerson
方法时,相应的文档也会从ElasticSearch中删除。
搜索API
Jkes提供了一个独立的搜索服务(jkes-search-service),它是一个基于Spring Boot的应用,提供RESTful搜索API。以下是一些常用的搜索示例:
- 简单查询
GET /api/v1/my_app_person/person/_search?q=name:John
- 复杂查询(使用JSON请求体)
POST /api/v1/my_app_person/person/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "John" } },
{ "range": { "age": { "gte": 30 } } }
],
"should": [
{ "term": { "gender": "male" } }
]
}
}
}
- 聚合查询
POST /api/v1/my_app_person/person/_search
{
"size": 0,
"aggs": {
"gender_count": {
"terms": { "field": "gender" }
},
"avg_age": {
"avg": { "field": "age" }
}
}
}
这些API允许开发人员执行各种复杂的搜索操作,包括全文搜索、过滤、排序和聚合等。
Jkes架构
Jkes的架构设计充分利用了Kafka和ElasticSearch的优势,实现了高效的索引更新和灵活的搜索功能。以下是Jkes的核心架构组件:
-
注解处理器: 负责解析实体类上的Jkes注解,生成元数据。
-
索引管理器: 基于元数据创建和更新ElasticSearch索引配置。
-
事件拦截器: 拦截JPA操作,生成索引更新事件。
-
Kafka生产者: 将索引更新事件发送到Kafka。
-
Kafka Connect: 使用自定义的连接器(jkes-index-connector和jkes-delete-connector)将事件从Kafka同步到ElasticSearch。
-
搜索服务: 提供RESTful搜索API,处理搜索请求并返回结果。
这种架构设计带来了以下优势:
- 解耦: 索引更新和搜索操作完全分离,提高了系统的可扩展性。
- 可靠性: 利用Kafka的特性确保数据不会丢失,即使在系统故障时也能保证最终一致性。
- 性能: 通过异步处理索引更新,减少了对主业务流程的影响。
- 灵活性: 搜索服务可以独立扩展,以应对高并发的搜索请求。
高级特性
除了基本的索引和搜索功能,Jkes还提供了一些高级特性,使其能够适应更复杂的应用场景:
1. 嵌套对象支持
Jkes支持索引和搜索嵌套对象,这对于处理复杂的数据结构非常有用。例如:
@Document
public class PersonGroup {
@Id
private Long id;
@Field(type = FieldType.Text)
private String name;
@Field(type = FieldType.Nested)
@OneToMany(mappedBy = "personGroup")
private List<Person> persons;
}
对应的嵌套查询:
{
"query": {
"nested": {
"path": "persons",
"query": {
"bool": {
"must": [
{ "match": { "persons.name": "John" } },
{ "range": { "persons.age": { "gte": 30 } } }
]
}
}
}
}
}
2. 多字段映射
Jkes允许为一个字段创建多个索引,以支持不同的查询需求:
@MultiFields(
mainField = @Field(type = FieldType.Text),
otherFields = {
@InnerField(suffix = "raw", type = FieldType.Keyword),
@InnerField(suffix = "english", type = FieldType.Text, analyzer = "english")
}
)
private String name;
这样可以同时支持全文搜索、精确匹配和特定语言的分析。
3. 自定义分析器
Jkes支持使用ElasticSearch的自定义分析器,以满足特定的文本处理需求:
@Field(type = FieldType.Text, analyzer = "my_custom_analyzer")
private String description;
4. 版本控制
Jkes利用ElasticSearch的版本机制来确保不会索引过期的文档数据:
@Version
private Long version;
5. 批量索引
对于大量数据的初始化索引,Jkes提供了批量索引功能:
indexer.startAll();
这个操作会启动一个后台任务,高效地将所有实体数据索引到ElasticSearch中。
6. 索引别名
Jkes支持为索引创建别名,这在进行索引重建或者版本升级时非常有用:
@Document(type = "person_group", alias = "person_group_alias")
public class PersonGroup { ... }
7. 动态映射
虽然Jkes鼓励使用明确的字段映射,但它也支持ElasticSearch的动态映射功能,允许索引未明确定义的字段。
性能优化
为了确保Jkes在生产环境中能够高效运行,可以考虑以下性能优化策略:
-
索引分片: 根据数据量和查询模式合理设置索引的分片数。
-
批量操作: 使用批量API进行大量文档的索引或更新操作。
-
查询优化: 使用过滤器缓存、聚合缓存等ElasticSearch提供的优化特性。
-
JVM调优: 为ElasticSearch和Kafka配置适当的JVM参数,以提高性能。
-
硬件优化: 使用SSD存储、增加内存等硬件升级方式提升整体性能。
最佳实践
在使用Jkes进行开发时,建议遵循以下最佳实践:
-
合理使用注解: 只索引必要的字段,避免过度索引。
-
规划索引策略: 根据业务需求设计合适的索引结构和映射。
-
异步处理: 对于非关键路径的索引更新,考虑使用异步处理。
-
监控和日志: 实施全面的监控和日志记录,及时发现和解决问题。
-
定期维护: 执行索引优化、别名切换等维护操作,保持系统健康。
-
安全考虑: 实施适当的安全措施,如身份验证、授权和加密。
结语
Jkes为Java开发者提供了一个强大而灵活的搜索解决方案。通过结合Java、Kafka和Elastic