Spring Data Elasticsearch介绍
1 资料收集
官方文档中文翻译
http://es.xiaoleilu.com/index.html
https://endymecy.gitbooks.io/elasticsearch-guide-chinese/content/index.html
官方英文文档
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-index.html
Spring Data Elasticsearch
2 Spring Data Elasticsearch提供功能
2.1 支持jpa
2.2 普通curd查询
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
//保存
<S extends T> S save(S entity);
//通过id查找
T findOne(ID primaryKey);
//获取所有对象
Iterable<T> findAll();
//获取的count
Long count();
//删除
void delete(T entity);
//判断是否存在
boolean exists(ID primaryKey);
// … more functionality omitted.
}
2.2 分页查询
简单分页查询
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
//排序查询所有的数据
Iterable<T> findAll(Sort sort);
//分页查询
Page<T> findAll(Pageable pageable);
}
比如想要查询前20条数据
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));
复杂带条件分页查询
Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
2.3 通用规范自定义查询
根据方法名字,自动查询,比如获取lastname为参数的数量
public interface UserRepository extends CrudRepository<User, Long> {
Long countByLastname(String lastname);
}
根据属性删除数据
public interface UserRepository extends CrudRepository<User, Long> {
Long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
查询例子
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
public interface PersonRepository extends Repository<User, Long> {
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
2.4 定义自己的通用repository
如果extend extend Repository, CrudRepository or PagingAndSortingRepository.
, CrudRepository
or PagingAndSortingRepository
. 这些都不满足你的通用自定义Repository
,可以通过使用@NoRepositoryBean
来定义通用自定义repository
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
T save(T entity);
}
interface UserRepository extends MyBaseRepository<User, Long> {
User findByEmailAddress(EmailAddress emailAddress);
}
2.5 支持java8 stream查询
这个我比较好奇,这个文档写到了spring data elasticsearch中,难道还支持sql,表示没有尝试过
@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();
try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
stream.forEach(…);
}
2.6 支持异步查询
@Async
Future<User> findByFirstname(String firstname);
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
@Async
ListenableFuture<User> findOneByLastname(String lastname);
2.7 Web Support
注解方式
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration { }
xml方式
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />
<!-- If you're using Spring HATEOAS as well register this one *instead* of the former -->
<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />
支持方式
主要是支持基础的WEB:
- 通过DomainClassConverter,允许spring mvc通过request parameters or path variables从repository 注入一个对象,这句话翻译得比较抽象,看看例子就知道了
HandlerMethodArgumentResolver 让spring mvc 支持解析 Pageable and Sort 两个参数
@Controller @RequestMapping("/users") public class UserController { @RequestMapping("/{id}") public String showUserForm(@PathVariable("id") User user, Model model) { model.addAttribute("user", user); return "userForm"; } }
上面的User对象是自动根据findOne这个方法从repository中查找对象并注入进去。
@Controller @RequestMapping("/users") public class UserController { @Autowired UserRepository repository; @RequestMapping public String showUsers(Model model, Pageable pageable) { model.addAttribute("users", repository.findAll(pageable)); return "users"; } }
上面列子演示了分页查询,可以自动识别参数并且减少很多代码去查询
参数 | 使用方式 |
---|---|
page | Page you want to retrieve, 0 indexed and defaults to 0. |
size | Size of the page you want to retrieve, defaults to 20. |
sort | sort=firstname&sort=lastname,asc 指定排序字段和方式 |
2.7 支持注解注解orm的方式去操作对象
@Document(indexName = "tb_article")
public class Article {
@Id
private int id;
@Field(type = FieldType.String, index = FieldIndex.analyzed, store = true)
private String content;
@Field(type = FieldType.String, index = FieldIndex.analyzed, store = true)
private String title;
@Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true)
private Date updateDate;
}
//保存数据并且索引
ArticleRepository articleRepository = (ArticleRepository) classPathXmlApplicationContext.getBean("articleRepository");
Article article = new Article();
article.setContent("2016-07-15 16:51:04,666 [main] DEBUG org.elasticsearch.threadpool - [Speed Demon] creating thread_pool [get], type [fixed], size [4], queue_size [1k]");
article.setTitle("我是标题");
article.setId(123);
articleRepository.save(article);
3 支持Elasticsearch的原生操作
3.1 支持filter的构建
private ElasticsearchTemplate elasticsearchTemplate;
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities =
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
3.2 用Scan And Scroll 来支持大数据量的数据
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices("test-index")
.withTypes("test-type")
.withPageable(new PageRequest(0,1))
.build();
String scrollId = elasticsearchTemplate.scan(searchQuery,1000,false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords){
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L , new ResultsMapper<SampleEntity>()
{
@Override
public Page<SampleEntity> mapResults(SearchResponse response) {
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
for(SearchHit searchHit : response.getHits()){
if(response.getHits().getHits().length <= 0) {
return null;
}
SampleEntity user = new SampleEntity();
user.setId(searchHit.getId());
user.setMessage((String)searchHit.getSource().get("message"));
chunk.add(user);
}
return new PageImpl<SampleEntity>(chunk);
}
});
if(page != null) {
sampleEntities.addAll(page.getContent());
hasRecords = page.hasNextPage();
}
else{
hasRecords = false;
}
}
}
4 配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd">
<elasticsearch:repositories base-package="com.main.com.es.main.repository"
/>
<elasticsearch:transport-client id="client"
cluster-nodes="192.168.114.109:9300"
cluster-name="searches"
/>
<bean name="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"/>
</bean >
</beans>
@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {
}
ElasticsearchTemplate
是一个可以操作原生Elasticsearch 的client的类配置后可以无缝的接入spring