ElasticSearchLinux安装和springboot整合的记录和遇到的问题

news2024/11/15 23:55:59

前面整合遇到的一些问题有的记录在下面了,有的当时忘了记录下来,希望下面的能帮到你们

1:Linux安装ES

下载安装:
参考文章:连接1

连接2

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.12.2-linux-x86_64.tar.gz

解压:tar -zxvf elasticsearch-8.12.2-linux-x86_64.tar.gz
这里注意,在bin目录下启动报错,因为不能通过root账户启动,需要新建账户

创建新用户给ES使用:adduser els
修改密码:echo 123456 | passwd --stdin els 或者:sudo passwd newpassword
然后将解压的es 目录赋予新创建的用户
sudo chown -R els:els /home/cdszwy/elasticsearch/elasticsearch-8.12.2
切换到新创建用户
su - els
然后进入解压目录的/bin 执行 ./elasticsearch -d 运行es
然后 执行curl http://127.0.0.1:9200显示

先要在防火墙打开该端口才能访问

安装遇到的问题:

  • Password: su: Permission denied

添加用户修改密码后,切换到新用户环境,再切换到root环境提示异常:Password: su: Permission denied
使用su命令时输入密码后提示权限限制,确认密码是正确的
即:

su root
Password:
su: permission denied

解决:
1.改变用户分组,将用户添加进wheel分组
#语法
#usermod [-G] [GroupName] [UserName]
usermod -G wheel username

2.修改/etc/pam.d/su
注释行:auth required pam_wheel.so use_uid

3:查看当前用户分组:
#语法
#id username
id els
#执行结果如下
uid=1001(els) gid=1001(els) groups=1001(els),10(wheel)

  • vm.max_map_count [65530] is too low

解决vm.max_map_count [65530] is too low问题
编辑 /etc/sysctl.conf 文件来永久更改该值。在文件的末尾添加下面一行并保存:vm.max_map_count=262144
然后可以通过运行以下命令重新加载配置文件:sudo sysctl -p

修改ES的配置:
修改配置:elasticsearch.yml

绑定到0.0.0.0,允许任何ip来访问

network.host: 0.0.0.0

#浏览器可直接访问

xpack.security.http.ssl:
enabled: false

末尾添加:

http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization

修改配置:jvm.options

-Xms1g
-Xmx1g

设置用户名密码:
在bin目录下执行:./elasticsearch-reset-password -u elskib -i
添加新用户给kibana使用
添加用户:./elasticsearch-users useradd elskib
分配绝俗: ./elasticsearch-users roles -a superuser elskib
账号:elskib
密码:qwe123

在启动ES
使用命令查看进程:
查看是否成功:ps -ef|grep elastic

IK分词器安装:https://github.com/infinilabs/analysis-ik/releases
下载再执行
在bin目录下执行命令:./elasticsearch-plugin install file:///home/cdszwy/elasticsearch/elasticsearch-analysis-ik-8.12.2.zip

2.springboot 整合ES

这里有一个区别:下面会有两种快速接口调用ES,分别是:使用RestHighLevelClient,使用ElasticsearchClient,先讲使用RestHighLevelClient

使用RestHighLevelClient

  • 引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

配置ES基础信息:

es:
  ip: 192.34.21.129
  port: 9200
  username: elskib
  password: qwe123

添加Java配置:

@Configuration
public class ElasticSearchConfig {

    @Value("${es.ip}")
    private String esIp;

    @Value("${es.port}")
    private Integer port;

    @Value("${es.username}")
    private String username;

    @Value("${es.password}")
    private String password;

    /**
     * 注册 rest高级客户端
     * @date   2024/3/5 16:01
     **/
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        // 创建CredentialsProvider,并设置用户名密码
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(username,password));
        // 创建RestHighLevelClient实例,并设置CredentialsProvider
        return new RestHighLevelClient(
                RestClient.builder(new HttpHost(esIp, port, "http"))
                        .setHttpClientConfigCallback(httpAsyncClientBuilder ->
                                httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                        )
        );
    }

添加方法的实现类:


import cn.test.vo.DocumentInfoPageVo;
import cn.test.vo.DocumentInfoVo;
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Description: 多条件操作文档
 * @version 1.0
 * @ClassName RestHighLevelServiceImpl
 * @date 2024/3/7 11:12
 **/
@Service
public class RestHighLevelServiceImpl {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    /**
     * 判断索引是否存在
     */
    public Boolean indexExists(String indexName) throws Exception {
        GetIndexRequest request = new GetIndexRequest(indexName);
        return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
    }

    /**
     * 创建 ES 索引
     */
    public CreateIndexResponse createIndex(String indexName, Settings.Builder settings, XContentBuilder mappings) throws Exception {
        //将 Settings 和 Mappings 封装到一个Request 对象中
        CreateIndexRequest request = new CreateIndexRequest(indexName)
                .settings(settings)
                .mapping(mappings);

        //通过 client 对象去连接ES并执行创建索引
        return restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
    }

    /**
     * 批量创建 ES 文档
     */
    public IndexResponse createDoc(String indexName, String id, String json) throws Exception {
        //准备一个Request对象
        IndexRequest request = new IndexRequest(indexName);
        //手动指定ID
        request.id(id);
        request.source(json, XContentType.JSON);
        //request.opType(DocWriteRequest.OpType.INDEX); 默认使用 OpType.INDEX,如果 id 重复,会进行  覆盖更新, resp.getResult().toString() 返回 UPDATE
        //request.opType(DocWriteRequest.OpType.CREATE); 如果ID重复,会报异常 =>  document already exists

        //通过 Client 对象执行添加
        return restHighLevelClient.index(request, RequestOptions.DEFAULT);
    }

    /**
     * 批量创建 ES 文档
     *
     * @param jsonMap Key = id,Value =  json
     */
    public BulkResponse batchCreateDoc(String indexName, Map<String, String> jsonMap) throws Exception {
        //准备一个Request对象
        BulkRequest bulkRequest = new BulkRequest();
        for (String id : jsonMap.keySet()) {
            IndexRequest request = new IndexRequest(indexName)
                    //手动指定ID
                    .id(id)
                    .source(jsonMap.get(id), XContentType.JSON);
            bulkRequest.add(request);
        }

        //通过 Client 对象执行添加
        return restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 自动补全 根据用户的输入联想到可能的词或者短语
     *
     * @param indexName 索引名称
     * @param field     搜索条件字段
     * @param keywords  搜索关键字
     * @param size      匹配数量
     * @return
     * @throws Exception
     */
    public List<String> suggest(String indexName, String field, String keywords, int size) throws Exception {
        //定义返回
        List<String> suggestList = new ArrayList<>();
        //构建查询请求
        SearchRequest searchRequest = new SearchRequest(indexName);
        //通过查询构建器定义评分排序
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        //构造搜索建议语句,搜索条件字段
        CompletionSuggestionBuilder completionSuggestionBuilder = new CompletionSuggestionBuilder(field);
        //搜索关键字
        completionSuggestionBuilder.prefix(keywords);
        //去除重复
        completionSuggestionBuilder.skipDuplicates(true);
        //匹配数量
        completionSuggestionBuilder.size(size);
        searchSourceBuilder.suggest(new SuggestBuilder().addSuggestion("article-suggest", completionSuggestionBuilder));
        //article-suggest为返回的字段,所有返回将在article-suggest里面,可写死,sort按照评分排序
        searchRequest.source(searchSourceBuilder);
        //定义查找响应
        SearchResponse suggestResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //定义完成建议对象
        CompletionSuggestion completionSuggestion = suggestResponse.getSuggest().getSuggestion("article-suggest");
        List<CompletionSuggestion.Entry.Option> optionsList = completionSuggestion.getEntries().get(0).getOptions();
        //从optionsList取出结果
        if (!CollectionUtils.isEmpty(optionsList)) {
            optionsList.forEach(item -> suggestList.add(item.getText().toString()));
        }
        return suggestList;
    }

    /**
     * 前缀查询,可以通过一个关键字去指定一个Field的前缀,从而查询到指定的文档
     */
    public SearchResponse prefixQuery(String indexName, String searchField, String searchKeyword) throws Exception {

        //创建Request对象
        SearchRequest request = new SearchRequest(indexName);

        //XX开头的关键词查询
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.prefixQuery(searchField, searchKeyword));
        request.source(builder);
        //执行查询
        return restHighLevelClient.search(request, RequestOptions.DEFAULT);
    }

    /**
     * 通过 QueryBuilder 构建多字段匹配如:QueryBuilders.multiMatchQuery("人工智能","title","content")
     * multi_match => https://www.cnblogs.com/vipsoft/p/17164544.html
     */
    public SearchResponse search(String indexName, QueryBuilder query, int currPage, int pageSize) throws Exception {
        SearchRequest request = new SearchRequest(indexName);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        int start = (currPage - 1) * pageSize;
        builder.from(start);
        builder.size(pageSize);
        builder.query(query);
        request.source(builder);
        return restHighLevelClient.search(request, RequestOptions.DEFAULT);
    }




    /**
     * Description:根据条件查询文档信息
     * 分页问题:《不能实现跳转分页》
     * @date   2024/3/7 11:19
     * @param  indexName 索引名称
     * @param  queryBuilder 查询条件
     * @param  pageSize 每页数量
     * @param  page 页码
     * @param  scrollId 下一页的请求ID
     * @return List<DocumentInfo> 返回所有文档信息
     **/
//    @Override
    public Object getDocPageList(String indexName, QueryBuilder queryBuilder, Integer pageSize, Integer page, String scrollId) throws IOException {
        List<Object> list = new ArrayList<>();
        //指定scroll信息,2分钟过期
        //失效时间为2min
        Scroll scroll = new Scroll(TimeValue.timeValueMinutes(2));
        Long totalCount = null;
        //首次查询scrollId为空
        if(StringUtils.isEmpty(scrollId)){
            //指定搜索索引
            SearchRequest searchRequest = new SearchRequest(indexName);
            //封存快照
            searchRequest.scroll(scroll);
            //指定条件对象
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //指定查询条件
            sourceBuilder.size(pageSize);
            sourceBuilder.sort("reportDate", SortOrder.DESC);
            sourceBuilder.query(queryBuilder);
            searchRequest.source(sourceBuilder);
            //参数 1:搜索请求对象 参数2: 请求配置对象 返回值:查询结果对象
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //计算总数量
            totalCount = searchResponse.getHits().getTotalHits().value;
//            //得到总页数
//            page = (int) Math.ceil((float) totalCount / 2);
            //多次遍历分页,获取结果
            scrollId = searchResponse.getScrollId();
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                System.out.println("id: "+hit.getId()+" source: "+hit.getSourceAsString());
                list.add(JSONUtil.toBean(JSONUtil.parseObj(hit.getSourceAsString()), Object.class));
            }
        } else {
            System.out.println("第二次查询");
            //TODO 只能连续分页查询,不能进行分页跳转查询
            //获取到该id
            SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
            searchScrollRequest.scroll(scroll);
            SearchResponse response = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
            //打印数据
            SearchHits searchHits = response.getHits();
            scrollId = response.getScrollId();

            for (SearchHit hit : searchHits) {
                System.out.println("id: "+hit.getId()+" source: "+hit.getSourceAsString());
                list.add(JSONUtil.toBean(JSONUtil.parseObj(hit.getSourceAsString()), Object.class));
            }
        }
        Object vo = new Object();
        vo.setTotal(totalCount);
//        vo.setScrollId(scrollId);
        vo.setList(list);
        return vo;
    }
}

这里的Object可以替换为你的实体类,想要解析的对象

使用ElasticsearchClient

  • 添加依赖:
        <!-- Elasticsearch8.12版本(Java API Client),使用ElasticsearchClient-->
        <dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
            <version>8.12.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>jakarta.json-api</artifactId>
                    <groupId>jakarta.json</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>8.12.2</version>
        </dependency>

        <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
            <version>2.1.1</version>
        </dependency>
  • 添加配置
package cn.test.configs;

import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

/**
 * Description: es配置累
 * @version 1.0
 * @ClassName ElasticSearchConfig
 * @date 2024/3/5 15:58
 **/
@Configuration
public class ElasticSearchConfig {

    @Value("${es.ip}")
    private String esIp;

    @Value("${es.port}")
    private Integer port;

    @Value("${es.username}")
    private String username;

    @Value("${es.password}")
    private String password;


    @Bean
    public ElasticsearchClient esRestClientWithCred(){
        final String scheme = "http";
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        // 配置连接ES的用户名和密码,如果没有用户名和密码可以不加这一行
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(esIp, port, scheme))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
                        return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    }
                });
        RestClient restClient = restClientBuilder.build();
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());
        return new ElasticsearchClient(transport);
    }

    /**
     * 异步方式
     *
     * @return
     */
    @Bean
    public ElasticsearchAsyncClient elasticsearchAsyncClient() {
        HttpHost[] httpHosts = toHttpHost();
        RestClient restClient = RestClient.builder(httpHosts).build();
        RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        return new ElasticsearchAsyncClient(transport);
    }


    /**
     * 解析配置的字符串hosts,转为HttpHost对象数组
     *
     * @return
     */
    private HttpHost[] toHttpHost() {
        if (!StringUtils.hasLength(esIp)) {
            throw new RuntimeException("invalid elasticsearch configuration. elasticsearch.hosts不能为空!");
        }

        // 多个IP逗号隔开
        String[] hostArray = esIp.split(",");
        HttpHost[] httpHosts = new HttpHost[hostArray.length];
        HttpHost httpHost;
        for (int i = 0; i < hostArray.length; i++) {
            String[] strings = hostArray[i].split(":");
            httpHost = new HttpHost(strings[0], port, "http");
            httpHosts[i] = httpHost;
        }

        return httpHosts;
    }
}

  • 实现类

索引操作

import cn.test.service.ElasticSearchIndexService;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.util.ObjectBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.function.Function;

/**
 * Description: ES索引操作
 * @version 1.0
 * @ClassName ElasticSearchIndexServiceImpl
 * @date 2024/3/6 14:05
 **/
@Service
@Slf4j
public class ElasticSearchIndexServiceImpl implements ElasticSearchIndexService {

    @Autowired
    private ElasticsearchClient elasticsearchClient;


    /**
     * Description:根据索引名称创建索引
     * @date   2024/3/6 14:09
     * @param  name 索引名称
     **/
    @Override
    public void createIndex(String name) throws IOException {
        //ApplicationContext applicationContext;
        CreateIndexResponse response = elasticsearchClient.indices().create(c -> c.index(name));
        log.info("createIndex方法,acknowledged={}", response.acknowledged());
    }

    /**
     * Description:索引创建
     * @date   2024/3/6 14:15
     * @param  name 索引名称
     * @param  settingFn 索引属性设置
     * @param  mappingFn mapping属性设置
     **/
    @Override
    public void createIndex(String name,
                            Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
                            Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException {
        CreateIndexResponse response = elasticsearchClient
                .indices()
                .create(c -> c
                        .index(name)
                        .settings(settingFn)
                        .mappings(mappingFn)
                );
        log.info("createIndex方法,acknowledged={}", response.acknowledged());
    }

    /**
     * Description:根据索引名称删除索引
     * @date   2024/3/6 14:10
     * @param  name 索引名称
     **/
    @Override
    public void deleteIndex(String name) throws IOException {
        DeleteIndexResponse response = elasticsearchClient.indices().delete(c -> c.index(name));
        log.info("deleteIndex方法,acknowledged={}", response.acknowledged());
    }

    /**
     * Description:根据索引名称设置mapping
     * @date   2024/3/6 14:12
     * @param  name 索引名称
     * @param  propertyMap 属性
     **/
    @Override
    public void updateIndexProperty(String name, HashMap<String, Property> propertyMap) throws IOException {
        PutMappingResponse response = elasticsearchClient.indices()
                .putMapping(typeMappingBuilder ->
                        typeMappingBuilder
                                .index(name)
                                .properties(propertyMap)
                );
        log.info("updateIndexMapping方法,acknowledged={}", response.acknowledged());
    }

    /**
     * Description:获取所有索引信息
     * @date   2024/3/6 14:13
     **/
    @Override
    public GetIndexResponse getIndexList() throws IOException {
        //使用 * 或者 _all都可以
        GetIndexResponse response = elasticsearchClient.indices().get(builder -> builder.index("_all"));
        log.info("getIndexList方法,response.result()={}", response.result().toString());
        return response;
    }

    /**
     * Description:根据索引名称获取所有详情
     * @date   2024/3/6 14:13
     * @param  name 索引名称
     * @return GetIndexResponse 返回信息
     **/
    @Override
    public GetIndexResponse getIndexDetail(String name) throws IOException {
        GetIndexResponse response = elasticsearchClient.indices().get(builder -> builder.index(name));
        log.info("getIndexDetail方法,response.result()={}", response.result().toString());
        return response;
    }

    /**
     * Description:根据索引名称判断索引是否存在
     * @date   2024/3/6 14:13
     * @param  name 索引名称
     * @return boolean 返回存在的布尔值
     **/
    @Override
    public boolean indexExists(String name) throws IOException {
        return elasticsearchClient.indices().exists(b -> b.index(name)).value();
    }
}

文档类

package cn.goktech.workbench.service.impl;

import cn.test.configs.PublicConfig;
import cn.test.entity.docmanagement.po.DocumentInfo;
import cn.test.entity.docmanagement.vo.DocumentInfoPageVo;
import cn.test.entity.docmanagement.vo.DocumentInfoVo;
import cn.test.service.ElasticSearchDocService;
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;

/**
 * Description: es操作文档的接口
 * @version 1.0
 * @ClassName ElasticSearchDocServiceImpl
 * @date 2024/3/6 17:44
 **/
@Service
@Slf4j
public class ElasticSearchDocServiceImpl implements ElasticSearchDocService {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private ElasticsearchAsyncClient elasticsearchAsyncClient;


    /**
     * 新增一个文档并返回ID
     * @param indexName 索引名称
     * @param document 文档对象
     * @return IndexResponse
     * @throws Exception 抛出操作异常
     */
    @Override
    public String createByFluentDsl(String indexName, DocumentInfo document) throws Exception {
        return  elasticsearchClient.index(idx -> idx
                .index(indexName)
                .id(document.getDocId())
                .document(document)).id();
    }


    /**
     * 新增一个文档
     * @param indexName 索引名称
     * @param document 文档对象 需要的字段自己创建一个实体类
     * @return IndexResponse
     * @throws Exception 抛出操作异常
     */
    @Override
    public String createByBuilderPattern(String indexName, DocumentInfo document) throws Exception {
        IndexRequest.Builder<Object> indexReqBuilder = new IndexRequest.Builder<>();
        indexReqBuilder.index(indexName);
        indexReqBuilder.id(document.getDocId());
        indexReqBuilder.document(document);
        return elasticsearchClient.index(indexReqBuilder.build()).id();
    }

    /**
     * 用JSON字符串创建文档
     * @param indexName 索引名称
     * @param idxId 索引id
     * @param jsonContent json字符串
     * @return IndexResponse
     * @throws Exception 抛出操作异常
     */
    @Override
    public String createByJson(String indexName, String idxId, String jsonContent) throws Exception {
        return elasticsearchClient.index(i -> i
                .index(indexName)
                .id(idxId)
                .withJson(new StringReader(jsonContent))).id();
    }

    /**
     * 异步新增文档
     * @param indexName 索引名称
     * @param idxId 索引id
     * @param document 文档内容 需要的字段自己创建一个实体类
     * @param action 属性
     */
    @Override
    public void createAsync(String indexName, String idxId, DocumentInfo document, BiConsumer<IndexResponse, Throwable> action) {
        elasticsearchAsyncClient.index(idx -> idx
                .index(indexName)
                .id(idxId)
                .document(document)
        ).whenComplete(action);
    }

    /**
     * 批量增加文档
     * @param indexName 索引名称
     * @param documents 要增加的对象集合 需要的字段自己创建一个实体类
     * @return 批量操作的结果
     * @throws Exception 抛出操作异常
     */
    @Override
    public BulkResponse bulkCreate(String indexName, List<DocumentInfo> documents) throws Exception {
        BulkRequest.Builder br = new BulkRequest.Builder();
        //可以将 Object定义为一个文档基类。比如 ESDocument类
        // 将每一个product对象都放入builder中
        documents.stream().forEach(esDocument -> br
                .operations(op -> op
                        .index(idx -> idx
                                .index(indexName)
                                .id(esDocument.getDocId())
                                .document(esDocument))));
        return elasticsearchClient.bulk(br.build());
    }

    /**
     * 根据文档id查找文档
     * @param indexName 索引名称
     * @param docId 文档id
     * @return Object类型的查找结果
     * @throws IOException 抛出操作异常
     */
    @Override
    public Object getById(String indexName, String docId) throws IOException {
        GetResponse<Object> response = elasticsearchClient.get(g -> g
                        .index(indexName)
                        .id(docId),
                Object.class);
        return response.found() ? response.source() : null;
    }

    /**
     * 根据文档id查找文档,返回类型是ObjectNode
     * @param indexName 索引名称
     * @param docId 文档id
     * @return ObjectNode类型的查找结果
     * @throws IOException 抛出操作异常
     */
    @Override
    public ObjectNode getObjectNodeById(String indexName, String docId) throws IOException {
        GetResponse<ObjectNode> response = elasticsearchClient.get(g -> g
                        .index(indexName)
                        .id(docId),
                ObjectNode.class);
        return response.found() ? response.source() : null;
    }

    /**
     * 根据文档id删除文档
     * @param indexName 索引名称
     * @param docId 文档id
     * @return Object类型的查找结果
     * @throws IOException 抛出操作异常
     */
    @Override
    public Boolean deleteById(String indexName, String docId) throws IOException {
        DeleteResponse delete = elasticsearchClient.delete(d -> d
                .index(indexName)
                .id(docId));
        return delete.forcedRefresh();
    }

    /**
     * 批量删除文档
     * @param indexName 索引名称
     * @param docIds 要删除的文档id集合
     * @return BulkResponse
     * @throws Exception 抛出操作异常
     */
    @Override
    public BulkResponse bulkDeleteByIds(String indexName, List<String> docIds) throws Exception {
        BulkRequest.Builder br = new BulkRequest.Builder();
        // 将每一个对象都放入builder中
        docIds.stream().forEach(id -> br
                .operations(op -> op
                        .delete(d -> d
                                .index(indexName)
                                .id(id))));
        return elasticsearchClient.bulk(br.build());
    }


    /**
     * Description:修改文档信息
     * @date   2024/3/7 10:09
     * @param  indexName 索引名称
     * @param  documentInfo 文档信息 需要的字段自己创建一个实体类
     **/
    @Override
    public void updateDocById(String indexName, DocumentInfo documentInfo) throws IOException {
        final UpdateResponse<DocumentInfo> response = elasticsearchClient.update(builder -> builder
                .index(indexName)
                .id(documentInfo.getDocId())
                .doc(documentInfo), DocumentInfo.class);
        System.err.println(response.shards().successful());
    }

    public void getDocPageList(String indexName, Integer pageNum, Integer pageSize) throws IOException {
        /*
         * 分页查询,查询所有
         * sort 排序
        */
        final SearchResponse<DocumentInfo> response = elasticsearchClient.search(builder ->
                        builder.index(indexName)
                                .query(q->q.matchAll(v->v))
                                .size(pageSize)
                                .from(pageNum)
                                .sort(builder1 -> builder1.field(f->f.field("reportDate").order(SortOrder.Desc)))
                , DocumentInfo.class);
        List<Hit<DocumentInfo>> hitList = response.hits().hits();
        System.err.println(hitList);
    }

    public void getDocPageListBySearchWords(String indexName, Integer pageNum, Integer pageSize, String searchWords) throws IOException {
        /*
         * 分页查询,可根据输入文字搜索
         * sort 排序
         */
        final SearchResponse<DocumentInfoVo> response = elasticsearchClient.search(builder ->
                        builder.index(indexName)
                                .query(q->q.multiMatch(v->v.query(searchWords).fields("docTitle", "docContent")))
                                .size(pageSize)
                                .from(pageNum)
                                .sort(builder1 -> builder1.field(f->f.field("reportDate").order(SortOrder.Desc)))
                , DocumentInfoVo.class);
        System.err.println(response);
    }

    public void getDocPageListByTitle(String indexName, Integer pageNum, Integer pageSize, String type) throws IOException {
        /*
         * 分页查询,可根据类型搜索
         * query 查询条件
         * sort 排序
         */
        final SearchResponse<DocumentInfoVo> response = elasticsearchClient.search(builder ->
                        builder.index(indexName)
                                .query(q->q.term(t ->t.field("docType.keyword").value(type)))
                                .size(pageSize)
                                .from(pageNum)
                                .sort(builder1 -> builder1.field(f->f.field("reportDate").order(SortOrder.Desc)))
                , DocumentInfoVo.class);
        System.err.println(response);
        List<Hit<DocumentInfoVo>> hitList = response.hits().hits();
    }


    /**
     * Description:TODOmethod
     * @date   2024/3/8 10:26
     * @param  indexName 索引名称
     * @param  pageNum 页码
     * @param  pageSize 每页数量
     * @param  queryList 查询条件query
     * @return DocumentInfoPageVo 返回分页数据
     * @throws IOException 抛出操作异常
     **/
    @Override
    public DocumentInfoPageVo getDocPageList(String indexName, Integer pageNum, Integer pageSize, List<Query> queryList) throws IOException {
        List<DocumentInfoVo> list = new ArrayList<>();
        SearchResponse<DocumentInfoVo> response = elasticsearchClient.search(s -> s
                        .index(indexName)
                        .query(q -> q.bool(b -> b.must(queryList)))
                        //高亮
                        .highlight(h -> h
                                .preTags("<span>")
                                .postTags("</span>")
                                .requireFieldMatch(false)
                                .fields("docTitle", hf -> hf)
                                .fields("docContent", hf -> hf))
                        //排序
                        .sort(sort -> sort.field(f -> f.field("reportDate").order(SortOrder.Desc)))
//                        //查询字段过滤
//                        .source(sc -> sc.filter(f -> f.includes(sources)))
                        //分页
                        .from((pageNum - 1) * pageSize)
                        .size(pageSize),
                DocumentInfoVo.class
        );
        DocumentInfoPageVo vo = new DocumentInfoPageVo();
        vo.setTotal(response.hits().total() != null ? response.hits().total().value() : PublicConfig.ZERO);

        System.err.println(response);

        List<Hit<DocumentInfoVo>> hitList = response.hits().hits();
        for (Hit<DocumentInfoVo> hit : hitList) {
            DocumentInfoVo infoVo = hit.source();
            if(Objects.nonNull(infoVo)){
                Map<String, List<String>> map = hit.highlight();
                //设置返回高亮的字段进行原字段替换
                infoVo.setDocTitle(CollectionUtils.isEmpty(map.get("docTitle")) ? infoVo.getDocTitle() : map.get("docTitle").get(PublicConfig.ZERO));
                infoVo.setDocContent(CollectionUtils.isEmpty(map.get("docContent")) ? infoVo.getDocContent() : map.get("docContent").get(PublicConfig.ZERO));
                list.add(infoVo);
            }
        }
        vo.setList(list);
        return vo;
    }
}

这里我想在分页多条件查询,使用方式:

try {
            //sources 为你过滤的字段,也就是你想要查询出来的字段,配置了那些字段才会返回那些字段
//            List<String> sources = new ArrayList<>();
            //queryList 为你想要的查询条件封装,每种查询方式的条件query不一样
            List<Query> queryList = new ArrayList<>();
            //根据文档类型筛选查询
            if(StringUtils.isNotEmpty(dto.getTypeName())){
                Query query = TermQuery.of(m -> m.field("docType.keyword").value(dto.getTypeName()))._toQuery();
                queryList.add(query);
            }
            //根据输入内容查询文档标签和文档内容
            if(StringUtils.isNotEmpty(dto.getSearchWord())){
                Query query = MultiMatchQuery.of(v -> v.query(dto.getSearchWord()).fields("docTitle", "docContent"))._toQuery();
                queryList.add(query);
            }
            //根据时间范围查询
            if(StringUtils.isNotEmpty(dto.getStartDate()) && StringUtils.isNotEmpty(dto.getEndDate())){
                long startTime = DateUtil.parse(dto.getStartDate()).getTime();
                Query startQuery = RangeQuery.of(r -> r.field("reportDate")
                        .gte(JsonData.of(startTime))
                )._toQuery();
                queryList.add(startQuery);
                long endTime = DateUtil.parse(dto.getEndDate()).getTime();
                Query endQuery = RangeQuery.of(r -> r.field("reportDate")
                        .lte(JsonData.of(endTime))
                )._toQuery();
                queryList.add(endQuery);
            }
            DocumentInfoPageVo pageVo = elasticSearchDocService.getDocPageList(DOC_INDEX, dto.getPage(), dto.getLimit(), queryList);
            return new PageResult<>(pageVo.getList(), pageVo.getTotal());

上面是我的分页查询,这里docType.keyword是为了匹配查询,如mysql中的 name=张三,我这里的docType在ES文档中的type就是keyword,MultiMatchQuery这个是我多字段分词查询,后面是范围查询。

在这里插入图片描述
上面这块可以看文章:这里讲了很多知识

文章查询并高亮显示可查看此文章

Elasticsearch Java API

ES的term查询无返回结果

学习和整合时推荐
ElasticSearch 所有知识总结

ElasticSearch(提高篇)

中文分词器(IK Analyzer)及自定义词库

以上简洁整理只是记录下,便于后期使用,希望对大家有所帮助

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1510214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何关闭微软的Edge浏览器右击提示的:“使用copilot重写“的提示?

最近在使用微软的edge浏览器写文档的时候&#xff0c;总是不小心右击鼠标&#xff0c;提示 有时候挺烦人的&#xff0c;那怎么关闭呢&#xff1f; 打开edge浏览器的设置 在设置中搜索AI&#xff0c;并关闭AI书写的选项就好了 这样就可以获得一个干净的界面了&#xff0c;不…

SPEL表达式及注入漏洞

SPEL,全称为Spring表达式语言&#xff0c;是一个由 Spring 框架提供的表达式语言。它是一种基于字符串的表达式语言&#xff0c;可以在运行时对对象进行查询和操作。 SpEL 支持在XML和注解配置中使用&#xff0c;它可以在Spring框架的各种组件中使用&#xff0c;如Spring MVC …

Visual grounding-视觉定位任务介绍

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

知识图谱技术综述

作者简介:徐增林(1980 − ),男,博士,教授,主要从事机器学习及其在社会网络分析、互联网、计算生物学、信息安全等方面的研究. 【摘要】 知识图谱技术是人工智能技术的重要组成部分,其建立的具有语义处理能力与开放互联能力的知识库,可在智能搜索、智能问答、个性化推…

Java中抽象类和接口有什么区别?

1、典型回答 接口和抽象类都是用来定义对象公共行为的&#xff0c;二者的主要区别有以下几点不同&#xff1a; 类型扩展不同&#xff1a;抽象类是单继承&#xff0c;而接口是多继承&#xff08;多实现&#xff09;方法/属性访问控制符不同&#xff1a;抽象类方法和属性使用访问…

Yolov8-车辆跟踪(BoT-SORT和ByteTrack算法)

这两种代码都是成熟的&#xff0c;直接调佣即可&#xff0c;下面是使用这两种算法的代码。 直观感受&#xff1a;ByteTrack预测的速度感觉比BoT-SORT快一些&#xff0c;流畅一些。 from ultralytics import YOLOmodel YOLO(yolov8n.pt)# results model.track(source".…

人工智能迷惑行为大赏

文章目录 每日一句正能量前言人工智能的“幽默”瞬间美好愿景背后的潜规则人工智能应用人脸识别视频监控分析自动驾驶/驾驶辅助 后记 每日一句正能量 把坚持当成一种习惯&#xff0c;别人光鲜的背后&#xff0c;都有加倍的付出&#xff0c;没有谁比谁更容易&#xff0c;只有谁比…

蚂蚁链摩斯荣获“艾瑞保险业数字化卓越服务商“奖

近日&#xff0c;艾瑞咨询发布《2023年中国保险业数字化转型研究报告》&#xff0c;摩斯隐私计算解决方案被报告入选&#xff0c;并获得“保险业数字化卓越服务商”奖。 蚂蚁摩斯是隐私计算行业的领先布局者&#xff1a;早在2017年&#xff0c;蚂蚁集团启动了隐私计算项目&…

【存储】ZYNQ+NVMe小型化全国产存储解决方案

文章目录 1、背景2、基础理论3、设计方案3.1、FPGA设计方案3.1.1、NVMe控制器实现3.1.2、NVMe控制器实现 3.2 驱动软件设计方案3.2.1 读写NVMe磁盘软件驱动3.2.2 NVMe磁盘驱动设计3.2.3 标准EXT4文件系统设计 3.3 上位机控制软件设计方案 4、测试结果4.1 硬件测试平台说明4.2 测…

HTML图片和多媒体标签

文章目录 1. 图片标签1.1. img 标签1.2. 相对路径1.3. 绝对路径 2. 多媒体标签2.1. 音频标签2.2. 视频标签 1. 图片标签 1.1. img 标签 img标签是用来加载图片的&#xff0c;比如我们加载一张喜羊羊的照片。 <!DOCTYPE html> <html lang"zh-CN"><h…

嵌入式学习37-TCP并发模型

TCP并发模型: 1.TCP多线程模型: 缺点: 1.创建线程会带来 资源开销 2.能够实现的 并发量 比较有限 2.IO模型: 1.阻塞IO: 没有…

Linux学习(1)——Linux文件目录

1.Linux目录层次标准 Linux文件系统最顶端的目录是——根目录&#xff1a;“/”&#xff0c;Linux所有文件和目录&#xff0c;都是挂载在根目录下面的。 可以在Linux终端中用“cd /”命令&#xff0c;进入到根目录下&#xff1b;再用“ls”命令&#xff0c;查看里面的各个子目录…

高级DBA带你处理MySQL集群爆表导致硬盘爆满系统产品宕机实际生产事故处理实战案例全网唯一

高级DBA带你处理MySQL集群爆表导致硬盘爆满系统产品宕机实际生产事故实战 一、事故描述 数据库某个表A其中用到了二进制字段&#xff0c;本来就无比巨大&#xff0c;再加上某个客户端阶段发生程序BUG&#xff0c;无限反复插入重复数据&#xff0c;导致一个大表一下午时间迅速…

网络地址转换协议NAT

网络地址转换协议NAT NAT的定义 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地IP地址&#xff08;即仅在本专用网内使用的专用地址&#xff09;&#xff0c;但现在又想和因…

Java剖析 : HashMap底层存储数据的结构 | HashSet添加不重复元素底层原理

HashSet底层剖析 前言&#xff1a; 我们知道Set中所存储的元素是不重复的&#xff0c;那么Set接口的实现类HashSet在添加元素时是怎么避免重复的呢&#xff1f; ★ HashSet在添加元素时&#xff0c;是如何判断元素重复的? ● 在底层会先调用hashCode()&#xff0c…

2024年春招助学活动:一批FPGA高端项目让你轻松拿到大厂offer

这里写目录标题 1、前言2、FPGA行业现状3、简历怎么写4、FPGA高端项目4.1 图像类&#xff1a;FPGA图像缩放多路视频拼接4.2 通信类&#xff1a;千兆网UDP协议栈4.3 通信类&#xff1a;万兆网UDP协议栈4.4 图像通信综合&#xff1a;FPGA图像缩放UDP网络视频传输4.5 图像高速接口…

Sora背后的技术《可控生成与文本到图像扩散模型》

在迅速发展的视觉生成领域中&#xff0c;扩散模型革命性地改变了景观&#xff0c;以其令人印象深刻的文本引导生成功能标志着能力的重大转变。然而&#xff0c;仅依赖文本来条件化这些模型并不能完全满足不同应用和场景的多样化和复杂需求。认识到这一不足&#xff0c;多项研究…

day41 动态规划part3

343. 整数拆分 中等 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 但是dp[0] 和 dp[1]为什么是0值得讨论&#xff0c;或者说不用讨论&#xff0c;压根…

Anybus获得IEC 62443-4-1工业网络安全标准ML3认证

HMS 工业网络旗下 Anybus 品牌已成功获得国际电工委员会&#xff08;IEC&#xff09;62443-4-1&#xff1a;安全产品开发生命周期要求&#xff08;一项工业网络安全标准&#xff09;的 3 级成熟度&#xff08;ML3&#xff09;认证。 该认证由全球知名的测试服务提供商 TV Rhein…

vite配置

"vite": "^5.1.4" resolve.alias&#xff1a;配置别名 1、执行npm install -D types/node 或者 yarn add types/node -D 2、以下配置代表访问src时可以用“”代替 resolve: {alias: {"": path.resolve(__dirname, "./src"),},}, 使…