ElasticSearch是一个开源的,分布式的,可扩展的全文搜索引擎,它可以快速的存储,搜索数据
ElasticcSearch是一个RESTful风格的搜哦和数据分析引擎,他的底层是Apache Lucene,Lucene使用过于复杂,因此ES应运而生,其使用JAVA编写,简单来说就是对Lucene去做了一层封装,提供了一套简单的API来帮助我们实现存储和检索的功能。
ES概述:
ES是面向文档的,这意味着它可以存储整个对象或者文档,并且他还有搜索功能,在ES中,你可以通过对文档进行索引,排序,搜索过滤
简单来讲
ES | 关系型数据库 |
---|---|
indice | 数据库 |
Type | 表 |
documents | 行 |
Fields | 列 |
index索引
ES数据管理的顶层单位就叫索引,相当于关系型数据库的数据库,index的命名必须是小写
一个索引就是一个拥有几分相似特征的文档的集合
比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。可类比mysql中的数据库
Document文档
index里的单条记录叫做文档,document使用JSON表示,同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
type类型
Document可以分组,比如employee里面可以按照部门分组,也可以按照职位分组,这种叫做虚拟的逻辑分组,类似
文档元数据Document MetaData
文档元数据分为index,type,id这三者可以唯一确定一个文档
Fields字段
每个Document的JSON都包含了需要的字段,每一个Key都代表一种Fields
节点node
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能
cluster集群
一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由 一个唯一的名字标识
分片和复制 shards&replicas
一个索引可以存储超出单个节点限制的海量数据,这是因为ES提供了将索引划分为多片的能力,这个就叫做分片,当你创建索引的时候可以指定分片数量,每个分片本身也是一个功能完善并且独立的索引
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
1.restful api
Elasticsearch 的 RESTful API 使用 HTTP 作为传输协议,使用 JSON 作为数据交换格式
因为是基于 HTTP 的 RESTFul API,所以向 Elasticsearch 发出的请求的组成部分与其它普通的 HTTP 请求是一样的
curl -X<VERB> -HContent-Type:application/json '://:/?' -d ''
2.ElasticsearchRepository
首先导入pom文件以及配置文件中进行配置
然后再业务方法中继承方法,举个例子
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {
//这里可以自定义方法
//比如可以定义
List<DiscussPost> findByXXX(String XXX);
//其中这里的XXX必须是DiscussPost里面的变量,比如DiscussPost里面有一个String entity,则上述方法可以变为
List<DiscussPost> findByEntity(String entity);
}
如果我们点进接口查看内部实现,可以发现
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T, ID> {
<S extends T> S index(S var1);
Iterable<T> search(QueryBuilder var1);
Page<T> search(QueryBuilder var1, Pageable var2);
Page<T> search(SearchQuery var1);
Page<T> searchSimilar(T var1, String[] var2, Pageable var3);
void refresh();
Class<T> getEntityClass();
}
有想进一步深究的小伙伴可以自己看一下源码,后期我应该还会开新坑去慢慢读一些源码,不过最近想的还是更快的把技术栈填到会上手的地步,所以帖子也都是偏实践为主
3.ElasticsearchTemplate
ElasticsearchTemplate是Spring对ES api的封装,提供大量的类完成各种查询。
找一下他的继承接口,大概知道他有哪些操作,如下
public interface ElasticsearchOperations {
ElasticsearchConverter getElasticsearchConverter();
Client getClient();
<T> boolean createIndex(Class<T> var1);
boolean createIndex(String var1);
boolean createIndex(String var1, Object var2);
<T> boolean createIndex(Class<T> var1, Object var2);
<T> boolean putMapping(Class<T> var1);
boolean putMapping(String var1, String var2, Object var3);
<T> boolean putMapping(Class<T> var1, Object var2);
<T> Map getMapping(Class<T> var1);
Map getMapping(String var1, String var2);
Map getSetting(String var1);
<T> Map getSetting(Class<T> var1);
<T> T queryForObject(GetQuery var1, Class<T> var2);
<T> T queryForObject(GetQuery var1, Class<T> var2, GetResultMapper var3);
<T> T queryForObject(CriteriaQuery var1, Class<T> var2);
<T> T queryForObject(StringQuery var1, Class<T> var2);
<T> Page<T> queryForPage(SearchQuery var1, Class<T> var2);
<T> Page<T> queryForPage(SearchQuery var1, Class<T> var2, SearchResultMapper var3);
<T> Page<T> queryForPage(CriteriaQuery var1, Class<T> var2);
<T> Page<T> queryForPage(StringQuery var1, Class<T> var2);
<T> Page<T> queryForPage(StringQuery var1, Class<T> var2, SearchResultMapper var3);
<T> CloseableIterator<T> stream(CriteriaQuery var1, Class<T> var2);
<T> CloseableIterator<T> stream(SearchQuery var1, Class<T> var2);
<T> CloseableIterator<T> stream(SearchQuery var1, Class<T> var2, SearchResultMapper var3);
<T> List<T> queryForList(CriteriaQuery var1, Class<T> var2);
<T> List<T> queryForList(StringQuery var1, Class<T> var2);
<T> List<T> queryForList(SearchQuery var1, Class<T> var2);
<T> List<String> queryForIds(SearchQuery var1);
<T> long count(CriteriaQuery var1, Class<T> var2);
<T> long count(CriteriaQuery var1);
<T> long count(SearchQuery var1, Class<T> var2);
<T> long count(SearchQuery var1);
<T> LinkedList<T> multiGet(SearchQuery var1, Class<T> var2);
<T> LinkedList<T> multiGet(SearchQuery var1, Class<T> var2, MultiGetResultMapper var3);
String index(IndexQuery var1);
UpdateResponse update(UpdateQuery var1);
void bulkIndex(List<IndexQuery> var1);
void bulkUpdate(List<UpdateQuery> var1);
String delete(String var1, String var2, String var3);
<T> void delete(CriteriaQuery var1, Class<T> var2);
<T> String delete(Class<T> var1, String var2);
<T> void delete(DeleteQuery var1, Class<T> var2);
void delete(DeleteQuery var1);
<T> boolean deleteIndex(Class<T> var1);
boolean deleteIndex(String var1);
<T> boolean indexExists(Class<T> var1);
boolean indexExists(String var1);
boolean typeExists(String var1, String var2);
void refresh(String var1);
<T> void refresh(Class<T> var1);
<T> Page<T> startScroll(long var1, SearchQuery var3, Class<T> var4);
<T> Page<T> startScroll(long var1, SearchQuery var3, Class<T> var4, SearchResultMapper var5);
<T> Page<T> startScroll(long var1, CriteriaQuery var3, Class<T> var4);
<T> Page<T> startScroll(long var1, CriteriaQuery var3, Class<T> var4, SearchResultMapper var5);
<T> Page<T> continueScroll(@Nullable String var1, long var2, Class<T> var4);
<T> Page<T> continueScroll(@Nullable String var1, long var2, Class<T> var4, SearchResultMapper var5);
<T> void clearScroll(String var1);
<T> Page<T> moreLikeThis(MoreLikeThisQuery var1, Class<T> var2);
Boolean addAlias(AliasQuery var1);
Boolean removeAlias(AliasQuery var1);
List<AliasMetaData> queryForAlias(String var1);
<T> T query(SearchQuery var1, ResultsExtractor<T> var2);
ElasticsearchPersistentEntity getPersistentEntityFor(Class var1);
}
最后放一段业务代码,主要的作用是对帖子进行搜索并且按照需要进行排序,中间的话ElasticsearchRepository和ElasticsearchTemplate都用到了,大伙可以看一下具体使用
@Service
public class ElasticsearchService {
@Autowired
private DiscussPostRepository discussRepository;
@Autowired
private ElasticsearchTemplate elasticTemplate;
public void saveDiscussPost(DiscussPost post) {
discussRepository.save(post);
}
public void deleteDiscussPost(int id) {
discussRepository.deleteById(id);
}
public Page<DiscussPost> searchDiscussPost(String keyword, int current, int limit) {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"))
.withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.withPageable(PageRequest.of(current, limit))
.withHighlightFields(
new HighlightBuilder.Field("title").preTags("").postTags(""),
new HighlightBuilder.Field("content").preTags("").postTags("")
).build();
return elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
SearchHits hits = response.getHits();
if (hits.getTotalHits() <= 0) {
return null;
}
List<DiscussPost> list = new ArrayList<>();
for (SearchHit hit : hits) {
DiscussPost post = new DiscussPost();
String id = hit.getSourceAsMap().get("id").toString();
post.setId(Integer.valueOf(id));
String userId = hit.getSourceAsMap().get("userId").toString();
post.setUserId(Integer.valueOf(userId));
String title = hit.getSourceAsMap().get("title").toString();
post.setTitle(title);
String content = hit.getSourceAsMap().get("content").toString();
post.setContent(content);
String status = hit.getSourceAsMap().get("status").toString();
post.setStatus(Integer.valueOf(status));
String createTime = hit.getSourceAsMap().get("createTime").toString();
post.setCreateTime(new Date(Long.valueOf(createTime)));
String commentCount = hit.getSourceAsMap().get("commentCount").toString();
post.setCommentCount(Integer.valueOf(commentCount));
// 处理高亮显示的结果
HighlightField titleField = hit.getHighlightFields().get("title");
if (titleField != null) {
post.setTitle(titleField.getFragments()[0].toString());
}
HighlightField contentField = hit.getHighlightFields().get("content");
if (contentField != null) {
post.setContent(contentField.getFragments()[0].toString());
}
list.add(post);
}
return new AggregatedPageImpl(list, pageable,
hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
}
});
}
}