ElasticSearch 7.10.1学习笔记

ElasticSearch

ElasticSearch安装

环境:> JDK1.8

下载地址

Windows下安装

下载完成后直接解压使用

在这里插入图片描述

运行完成后,访问http://localhost:9200/测试

在这里插入图片描述

安装可视化插件elasticsearch-head,需要node环境

  1. 下载地址:https://github.com/mobz/elasticsearch-head/releases
  2. 安装依赖:
cnpm install

npm run start

在这里插入图片描述

端口为9100,会出现跨域问题,先解决跨域

elasticsearch-7.10.1\config 下的elasticsearch.yml中加入

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

然后重启 ElasticSearch服务,访问:http://localhost:9100/

在这里插入图片描述

成功!这个工具就当作数据展示工具!我们后面所有的查询使用Kibana

安装Kibana

下载地址:https://www.elastic.co/cn/downloads/past-releases/kibana-7-10-1

Kibana 版本要和 ElasticSearch 版本一致

在这里插入图片描述

访问:http://localhost:5601/

在这里插入图片描述

IK分词器插件

如果要使用中文,建议使用IK分词器

什么是IK分词器?

分词:即把一段中文或者别的划分成一个个关键字,我们在搜索的时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,所以我们需要安装中文分词器ik来解决这个问题。

IK提供了两个分词算法,ik_smart和ik_max_word,其中ik_smart为最少切分,ik_max_word为最细粒度划分!

安装

下载地址:https://github.com/medcl/elasticsearch-analysis-ik

下载完毕之后,放入到我们的ElasticSearch插件即可

在这里插入图片描述

然后重启ES进行测试

ik_smart

在这里插入图片描述

ik_max_word

在这里插入图片描述

发现问题,我想要“在一直等待”,但是却被分开了,此时应该操作我们的字典

在这里插入图片描述

我们在ik的字典中,加入自己的字典,来使自己不愿意拆开的词保持完整。然后重启ES

在这里插入图片描述

可以看出我们的字典加载进来了。然后我们再次测试

在这里插入图片描述

我们要求不拆分的词,成功实现。以后,我们需要自己配置的分词,在ik分词的字典里加入即可。

ES Rest风格说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPNlMjyn-1616998211748)(F:\Users\笔记\assets\1616829900471.png)]

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
索引 类型 文件 字段
其中index、type是必须提供的。
id是可选的,不提供es会自动生成。
index、type将信息进行分层,利于管理。
index可以理解为数据库;type理解为数据表;id相当于数据库表中记录的主键,是唯一的。

关于索引的基本操作

测试

首先打开ES-head

创建一个索引

PUT /索引名/~类型名~(默认是_doc)/文档id
{
    请求体
}

在这里插入图片描述

完成了自动增加了索引!

在这里插入图片描述

数据类型

在这里插入图片描述

keyword就是一个整体,分析时不被拆分的类型

在这里插入图片描述

使用GET获取索引

在这里插入图片描述

查看默认类型

在这里插入图片描述

如果自己的文档字段没有指定,那么es就会给我们默认配置字段类型!

更新

推荐使用post方式,put方式需要把原来的所有值都需要提交,容易出错。post只需提交要修改的字段

在这里插入图片描述

在这里插入图片描述

删除

通过DELETE命令来实现删除,根据你请求来判断是删除索引还是删除文档记录!

在这里插入图片描述

关于文档的基本操作

执行操作,

  1. 添加数据
PUT /nanfeng/user/1
{
  "name": "南风",
  "age": 22,
  "desc": "一顿操作猛如虎",
  "tags": ["技术宅","健身达人","直男"]
  
}

PUT /nanfeng/user/2
{
  "name": "张三",
  "age": 29,
  "desc": "法外狂徒",
  "tags": ["旅游","交友","渣男"]
  
}

PUT /nanfeng/user/3
{
  "name": "李四",
  "age": 29,
  "desc": "mmp,不知道如何形容",
  "tags": ["美女","大长腿","沙雕"]
  
}

PUT /nanfeng/user/4
{
  "name": "南风学java",
  "age": 29,
  "desc": "mmp,不知道如何形容",
  "tags": ["美女","大长腿","沙雕"]
  
}
  1. 查询数据
GET nanfeng/user/1

带条件的搜索

GET nanfeng/user/_search?q=name:南风

在这里插入图片描述

复杂的查询(排序、分页、高亮)

模糊匹配

在这里插入图片描述

hit: 索引和文档的信息、查询的总数、然后就是查询出来的具体的文档。我们可以通过_socre获取更加符合的结果_

查询后结果的过滤,只查询其中两个

GET nanfeng/user/_search
{
  "query": {
    "match": {
      "name": "南风"
    }
  },
  "_source": ["name","desc"]
}

在这里插入图片描述

排序

GET nanfeng/user/_search
{
  "query": {
    "match": {
      "name": "南风"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

分页

GET nanfeng/user/_search
{
  "query": {
    "match": {
      "name": "南风"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ],
  "from": 0,	//从第几个数据开始
  "size": 1		//返回多少条数据
}

布尔查询

GET nanfeng/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "南风"
          }
        },
        {
          "match": {
            "age": 22
          }
        }
      ]
    }
  }
}

must-(and)、should-(or)

在这里插入图片描述

过滤

GET nanfeng/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "南风"
          }
        },
        {
          "match": {
            "age": 22
          }
        }
      ],
      "filter": [
        {
          "range": {
            "age": {
              "gte": 10,
              "lte": 25
            }
          }
        }
      ]
    }
  }
}

匹配多个条件

GET nanfeng/user/_search
{
  "query": {
    "match": {
      "tags": "男 技术"
    }
  }
}
//多个条件使用空格隔开,只要满足其中一个结果即可以被查出,这个时候可以通过分值判断。

精确查询

GET nanfeng/user/_search
{
  "query": {
    "term": {
      "name" : "南"
    }
  }
}

高亮查询

GET nanfeng/user/_search
{
  "query": {
    "match": {
      "name" : "南风"
    }
  },
  "highlight": {
    "pre_tags": "<p class='key' style='color:red'>", 
    "post_tags": "</p>", 
    "fields": {
      "name":{}
    }
  }
}

在这里插入图片描述

集成SpringBoot

文档 :https://www.elastic.co/guide/en/elasticsearch/client/index.html

本文使用文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

  1. 找到依赖
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.0</version>
</dependency>
  1. 找对象
RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

client.close();
  1. 分析类中的方法

配置基本的项目

在这里插入图片描述

问题:一定要保证我们导入的依赖和我们的es版本一致

<!--自己定义es版本依赖,保证和本地一致-->
<elasticsearch.version>7.10.1</elasticsearch.version>
/**
 * ElasticSearch 配置类
 *
 * @Author nanfeng
 * @Date 2021/3/27 17:21
 */
@Configuration
public class ElasticSearchConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }

}

实战

在这里插入图片描述

工具类

/**
 * ES工具类
 *
 * Relational DB -> Databases -> Tables -> Rows       -> Columns
 * Elasticsearch -> Indices   ->  Types -> Documents  -> Fields
 *                   索引          类型      文件           字段
 * 其中index、type是必须提供的。
 * id是可选的,不提供es会自动生成。
 * index、type将信息进行分层,利于管理。
 * index可以理解为数据库;type理解为数据表;id相当于数据库表中记录的主键,是唯一的。
 *
 * @Author nanfeng
 * @Date 2021/3/27 21:00
 */

@Slf4j
@Component
public class ElasticSearchUtil {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    /**
     * 创建索引
     *
     * @param index 索引
     * @return
     */
    public boolean createIndex(String index) throws IOException {
        if(isIndexExist(index)){
            log.error("Index is exits!");
            return false;
        }
        //1.创建索引请求
        CreateIndexRequest request = new CreateIndexRequest(index);
        //2.执行客户端请求
        CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

        log.info("创建索引{}成功",index);

        return response.isAcknowledged();
    }

    /**
     * 删除索引
     *
     * @param index
     * @return
     */
    public boolean deleteIndex(String index) throws IOException {
        if(!isIndexExist(index)) {
            log.error("Index is not exits!");
            return false;
        }
        //删除索引请求
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        //执行客户端请求
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);

        log.info("删除索引{}成功",index);

        return delete.isAcknowledged();
    }



    /**
     * 判断索引是否存在
     *
     * @param index
     * @return
     */
    public boolean isIndexExist(String index) throws IOException {

        GetIndexRequest request = new GetIndexRequest(index);

        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

        return exists;
    }



    /**
     * 数据添加,正定ID
     *
     * @param jsonObject 要增加的数据
     * @param index      索引,类似数据库
     * @param id         数据ID, 为null时es随机生成
     * @return
     */
    public String addData(JSONObject jsonObject, String index, String id) throws IOException {

        //创建请求
        IndexRequest request = new IndexRequest(index);
        //规则 put /test_index/_doc/1
        request.id(id);
        request.timeout(TimeValue.timeValueSeconds(1));
        //将数据放入请求 json
        IndexRequest source = request.source(jsonObject, XContentType.JSON);
        //客户端发送请求
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        log.info("添加数据成功 索引为: {}, response 状态: {}, id为: {}",index,response.status().getStatus(), response.getId());
        return response.getId();
    }


    /**
     * 批量添加数据
     *
     * @param index    索引,类似数据库
     * @param list     要增加的数据
     * @return
     * @throws IOException
     */
    public BulkResponse insertBatch(String index, List<T> list) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");

        for (T item : list) {
            IndexRequest indexRequest = new IndexRequest(index).source(JSON.toJSONString(item), XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        log.info("批量添加数据成功 索引为: {},response状态: {}", index, bulkResponse.status().getStatus());

        return bulkResponse;

    }


    /**
     * 批量删除数据
     *
     * @param index     索引,类似数据库
     * @param idList    要删除的数据id
     * @return
     * @throws IOException
     */
    public BulkResponse deleteBatch(String index, List<T> idList) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");

        for (T id : idList) {
            DeleteRequest deleteRequest = new DeleteRequest(index, id.toString());
            bulkRequest.add(deleteRequest);
        }
        BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        log.info("批量删除数据成功 索引为: {},response状态: {}", index, bulkResponse.status().getStatus());

        return bulkResponse;

    }


    /**
     * 数据添加 随机id
     *
     * @param jsonObject 要增加的数据
     * @param index      索引,类似数据库
     * @return
     */
    public String addData(JSONObject jsonObject, String index) throws IOException {
        return addData(jsonObject, index, IdUtils.fastSimpleUUID());
    }



    /**
     * 通过ID删除数据
     *
     * @param index 索引,类似数据库
     * @param id    数据ID
     */
    public void deleteDataById(String index, String id) throws IOException {
        //删除请求
        DeleteRequest request = new DeleteRequest(index, id);
        //执行客户端请求
        DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        log.info("索引为: {}, id为: {}删除数据成功",index, id);
    }


    /**
     * 通过ID 更新数据
     *
     * @param object     要增加的数据
     * @param index      索引,类似数据库
     * @param id         数据ID
     * @return
     */
    public void updateDataById(Object object, String index, String id) throws IOException {
        //更新请求
        UpdateRequest update = new UpdateRequest(index, id);

        update.timeout("1s");
        update.doc(JSON.toJSONString(object), XContentType.JSON);
        //执行更新请求
        UpdateResponse update1 = restHighLevelClient.update(update, RequestOptions.DEFAULT);
        log.info("索引为: {}, id为: {}, 更新数据成功",index, id);
    }


    /**
     * 通过ID 更新数据,保证实时性
     *
     * @param object     要增加的数据
     * @param index      索引,类似数据库
     * @param id         数据ID
     * @return
     */
    public void updateDataByIdNoRealTime(Object object, String index, String id) throws IOException {
        //更新请求
        UpdateRequest update = new UpdateRequest(index, id);

        //保证数据实时更新
        update.setRefreshPolicy("wait_for");

        update.timeout("1s");
        update.doc(JSON.toJSONString(object), XContentType.JSON);
        //执行更新请求
        UpdateResponse update1 = restHighLevelClient.update(update, RequestOptions.DEFAULT);
        log.info("索引为: {}, id为: {}, 更新数据成功",index, id);
    }


    /**
     * 通过ID获取数据
     *
     * @param index  索引,类似数据库
     * @param id     数据ID
     * @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
     * @return
     */
    public Map<String,Object> searchDataById(String index, String id, String fields) throws IOException {
        GetRequest request = new GetRequest(index, id);
        if (StringUtils.isNotEmpty(fields)){
            //只查询特定字段。如果需要查询所有字段则不设置该项。
            request.fetchSourceContext(new FetchSourceContext(true,fields.split(","), Strings.EMPTY_ARRAY));
        }
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        Map<String, Object> map = response.getSource();
        //为返回的数据添加id
        map.put("id",response.getId());
        return map;
    }

    /**
     * 通过ID判断文档是否存在
     * @param index  索引,类似数据库
     * @param id     数据ID
     * @return
     */
    public  boolean existsById(String index,String id) throws IOException {
        GetRequest request = new GetRequest(index, id);
        //不获取返回的_source的上下文
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
    }

    /**
     * 获取低水平客户端
     * @return
     */
    public RestClient getLowLevelClient() {
        return restHighLevelClient.getLowLevelClient();
    }


    /**
     * 高亮结果集 特殊处理
     * map转对象 JSONObject.parseObject(JSONObject.toJSONString(map), Content.class)
     * @param searchResponse
     * @param highlightField
     */
    public List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {
        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> high = hit.getHighlightFields();
            HighlightField title = high.get(highlightField);

            hit.getSourceAsMap().put("id", hit.getId());

            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            //解析高亮字段,将原来的字段换为高亮字段
            if (title!=null){
                Text[] texts = title.fragments();
                String nTitle="";
                for (Text text : texts) {
                    nTitle+=text;
                }
                //替换
                sourceAsMap.put(highlightField,nTitle);
            }
            list.add(sourceAsMap);
        }
        return list;
    }


    /**
     * 查询并分页
     * @param index          索引名称
     * @param query          查询条件
     * @param size           文档大小限制
     * @param from           从第几页开始
     * @param fields         需要显示的字段,逗号分隔(缺省为全部字段)
     * @param sortField      排序字段
     * @param highlightField 高亮字段
     * @return
     */
    public List<Map<String, Object>> searchListData(String index,
                                                    SearchSourceBuilder query,
                                                    Integer size,
                                                    Integer from,
                                                    String fields,
                                                    String sortField,
                                                    String highlightField) throws IOException {
        SearchRequest request = new SearchRequest(index);
        SearchSourceBuilder builder = query;
        if (StringUtils.isNotEmpty(fields)){
            //只查询特定字段。如果需要查询所有字段则不设置该项。
            builder.fetchSource(new FetchSourceContext(true,fields.split(","), Strings.EMPTY_ARRAY));
        }
        from = from <= 0 ? 0 : from*size;
        //设置确定结果要从哪个索引开始搜索的from选项,默认为0
        builder.from(from);
        builder.size(size);
        if (StringUtils.isNotEmpty(sortField)){
            //排序字段,注意如果proposal_no是text类型会默认带有keyword性质,需要拼接.keyword
            builder.sort(sortField+".keyword", SortOrder.ASC);
        }
        //高亮
        HighlightBuilder highlight = new HighlightBuilder();
        highlight.field(highlightField);
        //关闭多个高亮
        highlight.requireFieldMatch(false);
        highlight.preTags("<span style='color:red'>");
        highlight.postTags("</span>");
        builder.highlighter(highlight);
        //不返回源数据。只有条数之类的数据。
        //builder.fetchSource(false);
        request.source(builder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        log.error("=="+response.getHits().getTotalHits());
        if (response.status().getStatus() == 200) {
            // 解析对象
            return setSearchResponse(response, highlightField);
        }
        return null;
    }
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nan feng

打赏一杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值