ES搜索学习备份

1、搜索分类
 

顺序扫描:eg:使用like模糊搜索,select * from user where name like "%林%"
全文检索:
2、全文检索
  搜索原理概括:

内容爬取,停顿词过滤。eg:一些无用的像“的”,“了”子类的语气词/连接词
内容分词,提取关键字
根据关键词建立倒排索引
用户输入关键词进行搜索       
3、倒排索引
索引就类似于目录,平时使用的索引都是通过主键定位到数据,倒排索引刚好相反,就是通过数据定位到主键

正向索引
id    name    content
1    lin01    内容1
2    lin02    内容2
3    lin01    内容3
4    lin某某    内容2
通过id可以查询到name/content

反向索引
关键词    id
lin01    1,3
内容2    2,4
把name与content的字段抽取关键词。通过这个关键词搜索的时候,那么这个关键词就有可能出现在name/content字段内容中。

Elasticsearch 与 Mysql 对比:

        ES 里的 Index 可以看做一个库,而 Types 相当于表, Documents 则相当于表的行。这里 Types 的概念已经被逐渐弱化, Elasticsearch 6.X 中,一个 index 下已经只能包含一个type, Elasticsearch 7.X 中, Type 的概念已经被删除了。

4、ElasticSearch简介
ElasticSearch是什么:简称ES,是一个分布式、RESTful风格的搜索和数据分析引擎。

优势:

完美封装了Lucene核心库,设计了友好的Restful-API,开箱即用
分片与副本机制,只解决了集群下性能与高可用问题
ES主要几个版本特性:

5.x版本(大转折)
发布时间:2016.10.26
主要特性
Lucene 6.x 的支持,磁盘空间少一半;索引时间少一半;查询性能提升25%;支持IPV6。
Internal engine级别移除了用于避免同一文档并发更新的竞争锁,带来15%-20%的性能提升
提供了第一个Java原生的REST客户端SDK IngestNode
提供了 Painless 脚本,代替Groovy脚本
新增了Profile API
新增了Rollover API
新增Reindex
提供了第一个Java原生的REST客户端SDK,基于HTTP协议的客户端对Elasticsearch的依赖解耦,没有jar包冲突,提供了集群节点自动发现、日志处理、节点请求失败自动进行请求轮询,充分发挥Elasticsearch的高可用能力
引入新的字段类型 Text/Keyword 来替换 String
限制索引请求大小,避免大量并发请求压垮 ES
限制单个请求的 shards 数量,默认 1000 个
仅支持非root用户启动

6.x版本
发布时间:2017.08.31
主要特性
稀疏性 Doc Values 的支持
Index sorting,即索引阶段的排序
Removal of types,在 6.0 里面,开始不支持一个 index 里面存在多个 type
已经关闭的索引将也支持 replica 的自动处理,确保数据可靠
Load aware shard routing, 基于负载的请求路由,目前的搜索请求是全节点轮询,那么性能最慢的节点往往会造成整体的延迟增加,新的实现方式将基于队列的耗费时间自动调节队列长度,负载高的节点的队列长度将减少,让其他节点分摊更多的压力,搜索和索引都将基于这种机制。
顺序号的支持,每个 es 的操作都有一个顺序编号(类似增量设计)无缝滚动升级

7.x版本
发布时间:2019.04.10
主要特性
集群连接变化:TransportClient被废弃以至于es7的java代码,只能使用restclient。对于java编程,建议采用 High-level-rest-client 的方式操作ES集群
ES程序包默认打包jdk
Lucene9.0的支持
正式废除单个索引下多Type的支持,es6时,官方就提到了es7会删除type,并且es6时已经规定每一个index只能有一个type。在es7中使用默认的_doc作为type,官方说在8.x版本会彻底移除type。,api请求方式也发送变化,如获得某索引的某ID的文档:GET index/_doc/id其中index和id为具体的值
7.1开始,Security功能免费使用
ECK-ElasticSearch Operator on Kubernetes,支持k8s
支持Zen2 是 Elasticsearch 的全新集群协调层,提高了可靠性、性能和用户体验,变得更快、更安全,并更易于使用
Weak-AND算法提高查询性能
默认的Primary Shared数从5改为1,避免Over Sharding
间隔查询(Intervals queries) 某些搜索用例(例如,法律和专利搜索)引入了查找单词或短语彼此相距一定距离的记录的需要。 Elasticsearch 7.0中的间隔查询引入了一种构建此类查询的全新方式,与之前的方法(跨度查询span queries)相比,使用和定义更加简单。 与跨度查询相比,间隔查询对边缘情况的适应性更强
支持arm平台的包下载,包括kibana,logstash

5、安装ES(Linux-centos7)
ES版本下载地址:https://www.elastic.co/cn/downloads/past-releases#elasticsearch

找到对应版本下载 

注:ES不允许使用root账号启动服务,当前账号是root 就要用 su "账户名" eg:su es,没有另外一个账号就需要创建一个

# 创建用户并赋予相应的权限

adduser es

passwd es

chown -R es:es .

使用7.x以上的ES可以使用自带的jdk环境,环境配置:

        注意:yum -y install vim*    安装vim

        1、输入命令 echo $ES_JAVA_HOME  如有显示出路径,说明已经进行了配置,否则继续下一步。

        2、vim /etc/profile   在最下面添加,修改配置:

export ES_JAVA_HOME=/usr/local/es/elasticsearch-7.17.3/jdk
export ES_JRE_HOME=$ES_JAVA_HOME/jre
export CLASSPATH=$ES_JRE_HOME/lib:$ES_JRE_HOME/lib:$CLASSPATH
export PATH=$ES_JAVA_HOME/bin:$ES_JRE_HOME/bin:$PATH

        3、 vim config/elasticsearch.yml 文件修改

# 加入如下配置

network.host: 0.0.0.0     #ES开启远程访问
cluster.name: elasticsearch
node.name: node-1
http.port: 9200
cluster.initial_master_nodes: ["node-1"]

        4、修改虚拟机jvm堆内存大小 vim config/jvm.options 

-Xms1g

-Xmx1g

        5、修改/etc/security/limits.conf

# 在文件末尾中增加下面内容
# 每个进程可以打开的文件数的限制
es soft nofile 65536
es hard nofile 65536

        6、修改/etc/security/limits.d/20-nproc.conf

# 在文件末尾中增加下面内容
# 每个进程可以打开的文件数的限制
es soft nofile 65536
es hard nofile 65536
# 操作系统级别对每个用户创建的进程数的限制
* hard nproc 4096
# 注: * 带表 Linux 所有用户名称

        7、修改/etc/sysctl.conf

# 在文件中增加下面内容
# 一个进程可以拥有的 VMA(虚拟内存区域)的数量,默认值为 65536
vm.max_map_count=655360

        8、修改完sysctl.conf 之后 需要重新加载

sysctl -p

        9、默认配置,至少需要配置  discovery.seed_hosts / discovery.seed_providers / cluster.initial_master_nodes

discovery.seed_hosts: ["222.186.173.176"]  #自己linux的地址

# discovery.seed_providers:           基于配置文件配置集群主机列表
cluster.initial_master_nodes: ["node-1"]   #启动时初始化的参与选主的node,生产环境必填

启动ES

#非root用户 启动ES

bin/elasticsearch

# -d 后台启动

bin/elasticsearch -d

6、分词器(ik)插件
下载:https://github.com/medcl/elasticsearch-analysis-ik/releases 需要找到对应es的版本(版本相同)

下载完之后解压到es文件夹下的plugins目录下的ik目录(新建一个ik目录)

 注:在线下载到这个文件夹下时,记得要把压缩包删除

自定义词库:

1:现在对应的es版本的ik分词器的 jdbc-reload.properties 配置中配置对应的数据库地址:

2:添加热更新线程HotDictReloadThread

public class HotDictReloadThread implements Runnable {
 
    private static final Logger LOGGER = ESPluginLoggerFactory.getLogger(HotDictReloadThread.class.getName());
    @Override
    public void run() {
        while(true) {
            LOGGER.info("[==========]reload hot dict from mysql......");
            Dictionary.getSingleton().reLoadMainDict();
        }
    }
 
}
 并且需要启动热词字典加载线程,在 Dictionary 原文件中修改(找到 initial 方法中添加)

3:加载自定义数据库拓展词典到主词库表(在  Dictionary类中添加 loadExtendDictFromMysql 加载拓展词方法 与 loadStopDictFromMysql 加载停用词方法)

public void loadExtendDictFromMysql(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try{
            Path file = PathUtils.get(getDictRoot(),"jdbc-reload.properties");
            props.load(new FileInputStream(file.toFile()));
            logger.info("loading jdbc-reload.properties");
            for (Object key : props.keySet()) {
                logger.info(key + "=" + props.getProperty(String.valueOf(key)));
            }
            logger.info(" hot dict " + props.getProperty("jdbc.reload.extend.sql"));
            connection = DriverManager.getConnection(
                    props.getProperty("jdbc.url"),
                    props.getProperty("jdbc.user"),
                    props.getProperty("jdbc.password"));
            statement = connection.createStatement();
            resultSet = statement.executeQuery(props.getProperty("jdbc.reload.extend.sql"));
            while (resultSet.next()){
                // 加载扩展词典数据到主内存词典中
                String theWord = resultSet.getString("word");
                logger.info(theWord);
                _MainDict.fillSegment(theWord.trim().toLowerCase().toCharArray());
            }
            // 加载时间
            Thread.sleep(Integer.valueOf(String.valueOf(props.get("jdbc.reload.interval"))));
        }catch (Exception e){
            logger.error("[Extend Dict Loading] "+ e);
        }finally {
            if(resultSet != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    logger.error("[Extend Dict Loading] " + e);
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    logger.error("[Extend Dict Loading] " + e);
                }
            }
        }
    }
 
 
 
public void loadStopDictFromMysql(){
        // 建立主词典实例
        _StopWords = new DictSegment((char) 0);
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try{
            Path file = PathUtils.get(getDictRoot(),"jdbc-reload.properties");
            props.load(new FileInputStream(file.toFile()));
            logger.info("loading jdbc-reload.properties");
            for (Object key : props.keySet()) {
                logger.info(key + "=" + props.getProperty(String.valueOf(key)));
            }
            logger.info(" stop dict " + props.getProperty("jdbc.reload.stop.sql"));
            connection = DriverManager.getConnection(
                    props.getProperty("jdbc.url"),
                    props.getProperty("jdbc.user"),
                    props.getProperty("jdbc.password"));
            statement = connection.createStatement();
            resultSet = statement.executeQuery(props.getProperty("jdbc.reload.stop.sql"));
            while (resultSet.next()){
                // 加载扩展词典数据到主内存词典中
                String theWord = resultSet.getString("word");
                logger.info(theWord);
                _StopWords.fillSegment(theWord.trim().toLowerCase().toCharArray());
            }
            // 加载时间
            Thread.sleep(Integer.valueOf(String.valueOf(props.get("jdbc.reload.interval"))));
        }catch (Exception e){
            logger.error("[Stop Dict Loading] "+ e);
        }finally {
            if(resultSet != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    logger.error("[Stop Dict Loading] " + e);
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    logger.error("[Stop Dict Loading] " + e);
                }
            }
        }
    }
4:在 loadMainDict() 中添加自定义的加载拓展词的方法

5:在loadStopWordDict() 方法中添加自定义的加载停止词的方法

6:通过maven打包,

 注意:我这里使用的是es自带的jdk,所以要把ip和端口开通socket网络链接权限

 这个很重要!!!

到 es自带的 jdk/lib/security/default.policy文件中配置:

若不是使用es自带的jdk,那么常见的报错就是java.lang.ExceptionInInitializerError: null …access denied (“java.lang.RuntimePermission” “setContextClassLoader”)---配置内容位置相同

解决:
这是因为jdk权限不够

jdk14在/var/local/jdk-14.0.2/lib/security/default.policy中的grant{}里添加
jdk8是在/var/local/jdk1.8.0_271/jre/lib/security/java.policy中的grant{}里添加

permission java.lang.RuntimePermission "setContextClassLoader";


7、索引操作
创建索引:索引命名必须小写,不能以下划线开头

#创建索引     注:对比关系型数据库,创建索引就等同于创建数据库。

PUT  /es_db 

#创建索引可以设置分片数和副本数

PUT  /es_db

{

        "setting" : {

                "number_of_shards" : 3,

                "number_of_replicas" : 2

        }

}

#查询索引

GET  /es_db

#查询索引是否存在

HEAD  /es_db

#删除索引

DELETE  /ed_db

#关闭索引

POST  /es_db/_close

#打开索引

POST  /es_db/_open

#创建文档,指定id

PUT /es_db/_doc/1

{

        "name":"张三",

        "sex":1,

        "age":25,

        "address":"浙江杭州",

        "remark":"初学es"

}

#创建文档,指定id
PUT /es_db/_create/2
{
  "name":"李四",
  "sex":2,
  "age":18,
  "address":"浙江杭州",
  "remark":"初学es进阶"
}

#查询文档前10条信息内容
GET /es_db/_doc/_search

#查询对应id下的某一些信息
GET /es_db/_doc/1/_source

8、java-API操作elasticsearch
首先在pom中导入elasticsearch所需要的三个包

<!-- 使用elasticsearch必须导入的三个包 -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.1.0</version>
        </dependency>
创建索引
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
 
import java.io.IOException;
 
public class CreateIndex {
 
    public static void main(String[] args) throws IOException {
        // 创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));
 
        // 创建索引 - 请求对象
        CreateIndexRequest request = new CreateIndexRequest("user2");
        // 发送请求,获取响应
        CreateIndexResponse response = client.indices().create(request,
                RequestOptions.DEFAULT);
        boolean acknowledged = response.isAcknowledged();
        // 响应状态
        System.out.println("操作状态 = " + acknowledged);
 
        // 关闭客户端连接
        client.close();
    }
 
}
查询索引
import org.apache.http.HttpHost;
 
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
 
import java.io.IOException;
 
public class SearchIndex {
    public static void main(String[] args) throws IOException {
        // 创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));
 
        // 查询索引 - 请求对象
        GetIndexRequest request = new GetIndexRequest("user2");
        // 发送请求,获取响应
        GetIndexResponse response = client.indices().get(request,
                RequestOptions.DEFAULT);
        
        System.out.println("aliases:"+response.getAliases());
        System.out.println("mappings:"+response.getMappings());
        System.out.println("settings:"+response.getSettings());
 
        client.close();
    }
}
 删除索引
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
 
import java.io.IOException;
 
public class DeleteIndex {
    public static void main(String[] args) throws IOException {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));
        // 删除索引 - 请求对象
        DeleteIndexRequest request = new DeleteIndexRequest("user2");
        // 发送请求,获取响应
        AcknowledgedResponse response = client.indices().delete(request,RequestOptions.DEFAULT);
        // 操作结果
        System.out.println("操作结果 : " + response.isAcknowledged());
        client.close();
    }
}
写一个通用方法去连接并关闭elasticsearch
import org.elasticsearch.client.RestHighLevelClient;
 
public interface ElasticsearchTask {
 
    void doSomething(RestHighLevelClient client) throws Exception;
 
}
public class ConnectElasticsearch{
 
    public static void connect(ElasticsearchTask task){
        // 创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));
        try {
            task.doSomething(client);
            // 关闭客户端连接
            client.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 使用这个通用方法使用lambda表达式新增一条文档数据,并且附上直接连接elasticsearch并添加数据

package com.es.mian;
 
import com.es.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
 
import java.io.IOException;
 
public class InsertDoc {
    public static void main(String[] args) {
        ConnectElasticsearch.connect(client -> {
            // 新增文档 - 请求对象
            IndexRequest request = new IndexRequest();
            // 设置索引及唯一性标识
            request.index("user2").id("1001");
 
            // 创建数据对象
            User user = new User();
            user.setName("李四");
            user.setAge(18);
            user.setSex("女");
 
            ObjectMapper objectMapper = new ObjectMapper();
            String productJson = objectMapper.writeValueAsString(user);
            // 添加文档数据,数据格式为 JSON 格式
            request.source(productJson, XContentType.JSON);
            // 客户端发送请求,获取响应对象
            IndexResponse response = client.index(request, RequestOptions.DEFAULT);
            //3.打印结果信息
            System.out.println("_index:" + response.getIndex());
            System.out.println("_id:" + response.getId());
            System.out.println("_result:" + response.getResult());
        });
    }
 
    /*public static void main(String[] args) throws IOException {
        // 传入IP地址和端口号
        HttpHost httpHost = new HttpHost("localhost", 9200, "http");
        // 创建客户端对象
        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(httpHost));
        // 1.要在指定索引下创建文档,所以要先创建索引,再创建文档
        IndexRequest request=new IndexRequest();
        // index()方法设置索引名;id()方法设置唯一id标识
        request.index("user2").id("10001");
        // 2.创建实体类对象,填充数据
        User user=new User();
        user.setName("张三");
        user.setAge(30);
        user.setSex("男");
        // 3.利用jackson将实体类对象转换成JSON格式字符串
        ObjectMapper mapper=new ObjectMapper();
        String userJson = mapper.writeValueAsString(user);
        // 4.添加文档数据,数据格式为JSON格式
        request.source(userJson, XContentType.JSON);
        // 5.发送请求,获取响应结果
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println("_index: "+response.getIndex());
        System.out.println("_id: "+response.getId());
        System.out.println("_result: "+response.getResult());
        // 一番操作后,关闭客户端连接
        client.close();
    }*/
}
 
更新操作
package com.es.mian;
 
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;
 
public class UpdateDoc {
    public static void main(String[] args) {
        ConnectElasticsearch.connect(client -> {
            // 修改文档 - 请求对象
            UpdateRequest request = new UpdateRequest();
            // 配置修改参数
            request.index("user2").id("1001");
            // 设置请求体,对数据进行修改
            request.doc(XContentType.JSON, "name", "李四-修改之后的数据");
            // 客户端发送请求,获取响应对象
            UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
            System.out.println("_index:" + response.getIndex());
            System.out.println("_id:" + response.getId());
            System.out.println("_result:" + response.getResult());
        });
    }
 
}
 
查询user2索引下面的id为1001的文档数据内容
package com.es.mian;
 
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.RequestOptions;
 
public class GetDoc {
    public static void main(String[] args) {
        ConnectElasticsearch.connect(client -> {
            //1.创建请求对象
            GetRequest request = new GetRequest().index("user2").id("1001");
            //2.客户端发送请求,获取响应对象
            GetResponse response = client.get(request, RequestOptions.DEFAULT);
            //3.打印结果信息
            System.out.println("_index:" + response.getIndex());
            System.out.println("_type:" + response.getType());
            System.out.println("_id:" + response.getId());
            System.out.println("source:" + response.getSourceAsString());
        });
    }
}
 
 
 删除user2索引下面id为10001的文档数据
package com.es.mian;
 
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;
 
public class DeleteDoc {
    public static void main(String[] args) {
        ConnectElasticsearch.connect(client -> {
            //创建请求对象
            DeleteRequest request = new DeleteRequest().index("user2").id("10001");
            //客户端发送请求,获取响应对象
            DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
            //打印信息
            System.out.println(response.toString());
        });
    }
}
9、Kibana安装
下载对应elasticsearch的版本的kibana  eg:es版本为7.17.3 那么kibana下载7.17.3的版本 

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

2、对应压缩包放到对应目录 解压:tar -zxvf

10、ElasticSearch 基本概念
关系型数据库 与 ElasticSearch
在7.0之前,一个index可以设置多个Types
目前Type已经被Deprecated,7.0开始,一个索引只能创建一个Type - "_doc"
两者的区别
        ​

 文档(Document)
Elasticsearch 是面向文档的,文档是所有可能搜索数据的最小单位
文档会被序列化成JSON格式,保存在Elasticsearch中
每一个文档都有一个Unique ID
一篇文档包含了一系列字段,类似于数据库表中的一条记录
JSON文档,格式灵活,不需要预先定义格式
批量写入
批量对文档进行写操作失通过 _bulk 的API来实现的

请求方式:post
请求地址:_bulk
请求参数:通过_bulk操作文档,一般至少有两行参数(或偶行参数)
        -第一行参数为指定操作的类型及操作的对象(index,type和id)

        -第二行参数才是操作的数据

参数类似于:

{“actionName”:{"_index":"indexName","_type":"typeName","_id":"id"}}

{"field1":"value1","field2":"value2"}

# actionName:表示操作类型,主要操作类型有 create,index,delete和update

批量查询
        _mget批量读取

#批量读取对应index下的文档id,没有指定索引的_mget
GET _mget 

  "docs": [
      {
        "_index":"es_db",
        "_id": "1"
      },
      {
        "_index":"user2",
        "_id":"1"
      },
      {
        "_index":"user2",
        "_id":"2"

      }
    ]
}

#批量读取index为user2下的文档id,指定索引
GET /user2/_mget 

  "docs": [
      {
        "_id": "1"
      },
      {
        "_id":"2"
      },
      {
        "_id":"3"
      }
    ]
}

#进一步简化
GET /user2/_mget 

  "ids":["1","2","3"]
}

        _msearch: 在_msearch中,请求格式和bulk类似。查询一条数据需要两个对象,第一个设置index和type,第二个设置查询语句。查询语句和search相同。如果只是查询一个index,我们可以在url中带上indedx,这样,如果查询该index可以直接用空对象表示。

11、Easy-Es 的maven
 easy-es 接口官网:快速开始 | Easy-Es

 easy-es 主要是es结合了mybatis-plus,使用方式与mybatis-plus一样。

        <!-- 引入easy-es最新版本的依赖-->
        <dependency>
            <groupId>cn.easy-es</groupId>
            <artifactId>easy-es-boot-starter</artifactId>
            <!--这里Latest Version是指最新版本的依赖,比如2.0.0,可以通过下面的图片获取-->
            <version>Latest Version</version>
        </dependency>
 
        <!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch.client</groupId>
                    <artifactId>elasticsearch-rest-high-level-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.14.0</version>
        </dependency>
 Elasticsearch 基础语法:

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
 
//wildcardQuery 通配符查询,支持* 任意字符串;?任意一个字符
boolQuery.should(QueryBuilders.wildcardQuery("categoryId", "*"+item+"*"));
 
//termsQuery 分词精确查询
boolQuery.should(QueryBuilders.termsQuery("spuId", spuId));
 
//matchPhraseQuery 顺序相同不是指字段值的内容完全包含关键词,而是指分词顺序相同。
boolQuery.should(QueryBuilders.matchPhraseQuery("name", "黄山风景"));
//注意:此时分词搜索,name 为 "安徽黄山风景区"的内容,搜索不出来,因为"安徽黄山风景区"和"黄山风景"分词,发现分词"山风"和"风景"之间还间隔了"风景区"这个分词,所以不符合条件。
//解决可以设置slop解决分词间隔数量(分析:对第一条文档中的字段分词,"安徽黄山风景区"分词后发现安徽距离风景区相差两个字段,所以设置slop=2可以解决默认相隔字段为0的问题。)
boolQuery.should(QueryBuilders.matchPhraseQuery("name", "黄山风景").slop(2))
 
//matchQuery 即匹配查询。返回与提供的文本、数字、日期或布尔值匹配的文档。在匹配之前分析提供的文本。匹配查询是执行全文搜索的标准查询,包括模糊匹配选项。
boolQuery.should(QueryBuilders.matchQuery("dosTitle","我爱中华"))
 
//rangeQuery 范围查询
boolQuery.should(QueryBuilders.boolQuery().must(
       QueryBuilders.boolQuery()
          //定时上架时间 大于等于当前时间                                                                    
          .must(QueryBuilders.rangeQuery("offShelvesTime" ).gte(date.getTime()))   
          //定时下架时间 小于等于当前时间                                               
          .must(QueryBuilders.rangeQuery("putawayStartTime" ).lte(date.getTime())))
);
 
 
//条件写完之后,进行查询
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                        //查询条件
                        .withQuery(boolQuery)
                        //分页
                        .withPageable(PageRequest.of(pageNum, pageSize))
                        //排序
                        .withSort(sortBuilders.scoreSort().order(SortOrder.DESC));
val search = restTemplate.search(nativeSearchQueryBuilder.build(), EsGoodsSpuEs.class);
for (SearchHit<EsGoodsSpuEs> searchHit : search.getSearchHits()) {
                    list.add(searchHit.getContent());
}
map.put("total",search.getTotalHits()); //es搜索出来的总条数
map.put("list",list); //当前页数据list
重点需要注意的:
需要排序的字段,实体类型不能是 Bigdecimal 类型,否则排序会有问题(eg:字段类型为bigdecimal时,价格倒序时,价格为10.20 的商品会排在 价格为100的前面)
需要进行分词的字段 在es库中对应字段的 analyzer 要为 ik_max_word (这样在进行分词查询时,会把对应name字段分词,并且把搜索入参进行分词,然后进行匹配)
eg:"name" : {
          "type" : "text",
          "analyzer" : "ik_max_word"
        },

       3.使用matchPhraseQuery查询方法时,字段analyzer不要使用ik_max_word
————————————————
版权声明:本文为CSDN博主「Lin_XXiang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Lin_XXiang/article/details/127605205

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值