zl程序教程

您现在的位置是:首页 >  后端

当前栏目

JAVA学习实战(四)ElasticSearch原理及使用介绍

JAVAelasticsearch学习原理 介绍 实战 使用
2023-09-27 14:19:56 时间

ElasticSearch是一个开源的,分布式的,可扩展的全文搜索引擎,它可以快速的存储,搜索数据
ElasticcSearch是一个RESTful风格的搜哦和数据分析引擎,他的底层是Apache Lucene,Lucene使用过于复杂,因此ES应运而生,其使用JAVA编写,简单来说就是对Lucene去做了一层封装,提供了一套简单的API来帮助我们实现存储和检索的功能。

ElasticSearch相关概念

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允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制

ElasticSearch的使用

1.restful api
Elasticsearch 的 RESTful API 使用 HTTP 作为传输协议,使用 JSON 作为数据交换格式
因为是基于 HTTP 的 RESTFul API,所以向 Elasticsearch 发出的请求的组成部分与其它普通的 HTTP 请求是一样的

 curl -X<VERB> -HContent-Type:application/json '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'

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("<em>").postTags("</em>"),
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).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());
            }
        });
    }

}