Elasticsearch

Elasticsearch

1. Elasticsearch简介

Elasticsearch是一个基于Lucene的一个开源的分布式、RESTful 风格的搜索和数据分析引擎。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

2. Lucene 核心库

Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库——无论是开源还是私有,但它也仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理,因为Lucene 非常复杂。

为了解决Lucene使用时的繁复性,于是Elasticsearch便应运而生。它使用 Java 编写,内部采用 Lucene 做索引与搜索,但是它的目标是使全文检索变得更简单,简单来说,就是对Lucene 做了一层封装,它提供了一套简单一致的 RESTful API 来帮助我们实现存储和检索。

在这里插入图片描述

3. 和solr对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-foNYb2iW-1671947370518)(images\2.png)]
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

ElasticSearch对比 Solr 总结

项目ESSolr
安装简单,开箱即用复杂
分布式自带分布式协调管理功能利用zookeeper分布式管理
支持类型JSONJSON,XML,CSV
功能注重核心功能,其他功能借助于第三方插件提供功能更多
查询速度建立索引快,查询慢,实时查询快,推特,新浪实时应用查询快,增删改查慢,传统应用
社区学习成本高,开发维护者少,更新快社区成熟

4. 倒排索引(重点)

正排索引根据id 找到对应的一组数据 (B+tree 聚簇索引)

非聚簇索引:给一个字段建立索引,查询的时候 根据这个字段查到这行数据对应的id。回表,再根据id 去查 聚簇索引 从而拿到一行数据。

4.1正排索引

在这里插入图片描述

4.2 倒排索引

在这里插入图片描述

一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的 Term 列表。

4.3 分词

就是按照一定的规则,将一句话分成组合的单词,按照国人喜欢来进行的

海上生明月 - 如何分成 ----->海上 | 生 | 明月

4.4模拟一个倒排索引

原理步骤:
1. 将数据存入mysql之前,对其进行分词
2. 将分词和存入后得到的id,存放在数据结构中Map<String,Set<Integer>> index
1. 查询时先分词,然后从index中拿到Set<Integer> ids
1. 再根据ids 查询mysql,从而得到结果,这样借助了mysql的B+tree索引,提高性能

4.4.1创建项目

引入第三方结巴分词器依赖

<dependency>
    <groupId>com.huaban</groupId>
    <artifactId>jieba-analysis</artifactId>
    <version>1.0.2</version>
</dependency>

4.4.2注入分词器

/**
 * 往IOC容器中入住结巴分词组件
 *
 * @return
 */
@Bean
public JiebaSegmenter jiebaSegmenter() {
    return new JiebaSegmenter();
}

4.4.3测试分词器

@Autowired
public JiebaSegmenter jiebaSegmenter;

@Test
void testJieBa() {
    String words = "华为 HUAWEI P40 Pro 麒麟990 5G SoC芯片 5000万超感知徕卡四摄 50倍数字变焦 8GB+256GB零度白全网通5G手机";
    // 使用结巴分词,对字符串进行分词,分词类型为搜索类型
    List<SegToken> tokens = jiebaSegmenter.process(words, JiebaSegmenter.SegMode.INDEX);
    // 遍历,拿到SegToken对象中的word属性,打印结果
    tokens.stream()
            .map(token -> token.word)
            .collect(Collectors.toList())
            .forEach(System.out::println);
}

5.商品搜索案例

使用倒排索引加分词器,展示商品搜索功能

5.1创建实体类Goods

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
    /**
     * 商品的id
     */
    private Integer goodsId;

    /**
     * 商品的名称(主要分词和检索字段)
     */
    private String goodsName;

    /**
     * 商品的价格
     */
    private Double goodsPrice;
    
}

5.2模拟数据库,新建DBUtil类

public class DBUtil {
    /**
     * 模拟数据库,key=id,value=商品对象
     * 这里也可以使用List来模拟
     */
    public static Map<Integer, Goods> db = new HashMap<>();

    /**
     * 插入数据库
     *
     * @param goods
     */
    public static void insert(Goods goods) {
        db.put(goods.getGoodsId(), goods);
    }


    /**
     * 根据id得到商品
     *
     * @param id
     * @return
     */
    public static Goods getGoodsById(Integer id) {
        return db.get(id);
    }

    /**
     * 根据ids查询商品集合
     *
     * @param ids
     * @return
     */
    public static List<Goods> getGoodsByIds(Set<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<Goods> goods = new ArrayList<>(ids.size() * 2);
        // 循环ids
        ids.forEach(id -> {
            // 从数据库拿到数据
            Goods g = db.get(id);
            if (!ObjectUtils.isEmpty(g)) {
                goods.add(g);
            }
        });
        return goods;
    }
}

5.3创建GoodsService接口

public interface GoodsService {

    /**
     * 添加商品的方法
     *
     * @param goods
     */
    void addGoods(Goods goods);

    /**
     * 根据商品名称查询
     *
     * @param name
     * @return
     */
    List<Goods> findGoodsByName(String name);

    /**
     * 根据关键字查询
     *
     * @param keywords
     * @return
     */
    List<Goods> findGoodsByKeywords(String keywords);

}

5.4模拟倒排索引类

//倒排索引
public class InvertedIndex {
    //倒排索引key=分词, value=ids
    public static Map<String, Set<Integer>> index=new HashMap<>();
}

5.5 创建GoodsServiceImpl实现类

@Service
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    private JiebaSegmenter jiebaSegmenter;

    /**
     * 添加商品的方法
     * 1.先对商品名称进行分词,拿到了List<String> tokens
     * 2.将商品插入数据库 拿到商品id
     * 3.将tokens和id放入倒排索引中index
     *
     * @param goods
     */
    @Override
    public void addGoods(Goods goods) {
        // 分词
        List<String> keywords = fenci(goods.getGoodsName());
        // 插入数据库
        DBUtil.insert(goods);
        // 保存到倒排索引中
        saveToInvertedIndex(keywords, goods.getGoodsId());
    }

    /**
     * 保存到倒排索引的方法
     *
     * @param keywords
     * @param goodsId
     */
    private void saveToInvertedIndex(List<String> keywords, Integer goodsId) {
        // 拿到索引
        Map<String, Set<Integer>> index = InvertedIndex.index;
        // 循环分词集合
        keywords.forEach(keyword -> {
            Set<Integer> ids = index.get(keyword);
            if (CollectionUtils.isEmpty(ids)) {
                // 如果之前没有这个词 就添加进去
                HashSet<Integer> newIds = new HashSet<>(2);
                newIds.add(goodsId);
                index.put(keyword, newIds);
            } else {
                // 说明之前有这个分词 我们记录id
                ids.add(goodsId);
            }
        });
    }

    /**
     * 分词的方法
     *
     * @param goodsName
     * @return
     */
    private List<String> fenci(String goodsName) {
        List<SegToken> tokens = jiebaSegmenter.process(goodsName, JiebaSegmenter.SegMode.SEARCH);
        return tokens.stream()
                .map(token -> token.word)
                .collect(Collectors.toList());
    }

    /**
     * 根据商品名称查询
     *
     * @param name
     * @return
     */
    @Override
    public List<Goods> findGoodsByName(String name) {
        // 查询倒排索引中 是否有这个词
        Map<String, Set<Integer>> index = InvertedIndex.index;
        Set<Integer> ids = index.get(name);
        if (CollectionUtils.isEmpty(ids)) {
            // 查询数据库 模糊匹配去
        } else {
            // 说明分词有 根据ids 查询数据库
            return DBUtil.getGoodsByIds(ids);
        }
        return Collections.emptyList();
    }

    /**
     * 根据关键字查询
     *
     * @param keywords
     * @return
     */
    @Override
    public List<Goods> findGoodsByKeywords(String keywords) {
        // 进来先把关键字分词一下
        List<String> tokens = fenci(keywords);
        // 拿到倒排索引
        Map<String, Set<Integer>> index = InvertedIndex.index;
        Set<Integer> realIds = new HashSet<>();
        // 循环分词集合 查询倒排索引
        tokens.forEach(token -> {
            Set<Integer> ids = index.get(token);
            if (!CollectionUtils.isEmpty(ids)) {
                // 如果局部的ids不为空,就添加到总的ids里面去
                realIds.addAll(ids);
            }
        });
        // 查询数据库
        return DBUtil.getGoodsByIds(realIds);
    }
}

5.6编写测试类

@Test
    public void testMyIndex() throws Exception {
        // 造数据
        Goods goods = new Goods(1, "苹果手机", 10.00);
        Goods goods1 = new Goods(2, "华为手机", 11.00);
        Goods goods2 = new Goods(3, "红米手机", 5.00);
        Goods goods3 = new Goods(4, "联想手机", 6.00);
        Goods goods4 = new Goods(5, "联想笔记本", 8916.00);
        Goods goods5 = new Goods(6, "小米笔记本", 6983.5);
        goodsService.addGoods(goods);
        goodsService.addGoods(goods1);
        goodsService.addGoods(goods2);
        goodsService.addGoods(goods3);
        goodsService.addGoods(goods4);
        goodsService.addGoods(goods5);
        // 查询
       goodsService.findGoodsByName("苹果手机").forEach(System.out::println);

        goodsService.findGoodsByKeywords("苹果小米联想").forEach(System.out::println);
    }


6.Elasticsearch安装

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

使用比较新的版本7.15.2

6.1目录

在这里插入图片描述

bin:启动脚本
config:elasticsearch.yml,ES的集群信息、对外端口、内存锁定、数据目录、跨域访问等属性的配置
jvm.options,ES使用Java写的,此文件用于设置JVM相关参数,如最大堆、最小堆
log4j2.properties,ES使用log4j作为其日志框架
data:数据存放目录(索引数据)
plugins: ES的可扩展插件存放目录,如可以将ik中文分词插件放入此目录,ES启动时会自动加载

6.2 Elasticsearch可视化插件的安装

6.2.1谷歌插件方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AjxSHC5r-1671947370522)(images\9.png)]

6.2.2解决跨域问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4IuC5Jwx-1671947370523)(images\10.png)]

如果是远程访问,涉及到跨域访问,报错,解决方式如下:

修改elasticsearch.yml配置文件
http.cors.enabled: true
http.cors.allow-origin: "*"

6.3IK分词的安装【重点】

Ik分词在es 里面也是插件的形式安装的

{
    "analyzer":"standard",
    "text":"我要学习java"
}

在这里插入图片描述

6.3.1安装分词器

  1. 找对应的ES版本的IK分词 https://github.com/medcl/elasticsearch-analysis-ik/releases
  2. 下载后拷贝到plugins目录下
  3. 重启测试

6.3.2分词器类型

Ik分词的两种方式:

ik_smart:分词的粒度较小,也叫智能分词

在这里插入图片描述

**ik_max_word:**分词的粒度较大,也叫最大力度分词

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZHdnq9bc-1671947370525)(images\13.png)]

7.Elasticsearch核心概念【重点】

一个json串 叫文档 es又被叫文档性数据库

7.1 结构说明

ElasticsearchMysql
Index(索引库)Database(数据库)
Type(_doc)Table(表)
Document(文档)Row(行)
Field(字段)Column(列)
mappings列的类型约束(int,varchar…)

这里的Type概念从ES6.x以后被弱化,官方将在ES8.0以后正式剔除了。

7.2 索引库(indices)

把数据写入elasticsearch 时,会在里面建立索引,索引库里面存储索引,一个index 对应一个database

7.3 文档(document)

就是一条数据,一般使用json 表示,和数据库对比,就是一行数据,在java 里面就是一个对象

7.4 字段(field)

一个对象的属性,对应数据库就是一列

7.5 节点

一台运行elasticsearch的服务器,被称为一个节点

7.6 集群

多个节点组成一个集群

7.7 分片

一个索引可以存储在多个主分片上,有负载均衡的作用,还有从分片是主分片的一个副本

7.8 副本

一份数据可以有多个副本,做数据冗余(安全),一般放在从分片里面
在这里插入图片描述

8. Elasticsearch基本使用(重点)

Elasticsearch 是基于restful风格的http应用,Restful风格就是使用http动词形式对url资源进行操作(GET,POST,PUT,DELETE…)

操作格式为:

请求类型 ip:port/索引名/_doc/文档id
{请求体}

8.1 对索引和mappings的操作(建库建表约束)

8.1.1 新增索引

PUT http://192.168.226.128:9200/student 新建一个student索引,给定几个字段约束,索引只能增删,不能修改

{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "age":{
        "type": "integer"
      },
      "birthDay":{
        "type": "date"
      },
      "price":{
        "type": "double"
      }
    }
  }
}

8.1.2查询索引

在这里插入图片描述

8.1.3查询索引的mappings信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OBVOe0e1-1671947370527)(images\16.png)]

8.1.4 删除索引

DELETE http://192.168.226.128:9200/student

8.2 对Document的操作

8.2.1 新增数据

使用put请求新增时需要自己指定id,使用post请求新增时系统会自动生成一个id

PUT http://192.168.226.128:9200/user/_doc/1 

user: 索引名称

doc:类型(即将剔除,官方建议全部使用doc)

1: 文档id

在这里插入图片描述

从head插件里面查看数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dztvhf8t-1671947370528)(images\18.png)]

8.2.2 修改一个数据

  1. 危险的修改,把其他的字段值都删了

PUT http://192.168.226.128:9200/user/_doc/2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S9Z8iLRE-1671947370528)(images\19.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tqj2zi1g-1671947370529)(images\20.png)]

2.安全的修改,其他的字段值会保留

POST http://192.168.226.128:9200/user/_doc/2/_update

在这里插入图片描述

在这里插入图片描述

8.2.3 删除一个数据

DELETE http://192.168.226.128:9200/user/_doc/3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WxcFm2UM-1671947370530)(images\23.png)]

8.2.4查询一个数据

GET http://192.168.226.128:9200/user/_doc/1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYl9uNFh-1671947370531)(images\25.png)]

8.2.5 查询全部数据

GET http://192.168.226.128:9200/user/_doc/_search

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HaFtriAH-1671947370531)(images\26.png)]

9.SpringBoot使用ES【重点】

9.1创建项目,添加ES依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

9.2修改配置application.yml

spring:
    elasticsearch:
        uris: http://192.168.226.129:9200

9.3 测试连接ES

说明我们连接成功,下面开始操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tAEoIzNR-1671947370531)(C:\Users\mengyang\Documents\Elasticsearch\images\27.png)]

9.1 Java对索引的操作

9.1.1 新建Goods实体类

/**
 * @Document是ES提供的注解 indexName:索引名称
 * createIndex:启动时是否创建
 * shards:分片个数
 * replicas:副本个数
 * refreshInterval:数据导入到索引里面,最多几秒搜索到
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Setting(shards = 2,replicas = 1,refreshInterval = "1s")
@Document(indexName = "goods_index")
public class Goods {

    /**
     * 商品ID
     */
    @Id //默认使用keyword关键字模式,不进行分词
    @Field
    private Integer goodsId;
    /**
     * 商品名称
     * analyzer:插入时使用的分词,如果不设置使用ES预设的
     * searchAnalyzer:搜索时使用的分词,如果不设置使用analyzer,最后使用ES预设
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String goodsName;
    /**
     * 商品描述
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String goodsDesc;
    /**
     * 商品价格
     */
    @Field(type = FieldType.Double)
    private Double goodsPrice;
    /**
     * 商品的销量
     */
    @Field(type = FieldType.Long)
    private Long goodsSaleNum;
    /**
     * 商品的卖点
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String goodsBrief;
    /**
     * 商品的状态
     */
    @Field(type = FieldType.Integer)
    private Integer goodsStatus;
    /**
     * 商品的库存
     */
    @Field(type = FieldType.Integer)
    private Integer goodsStock;
    /**
     * 商品的标签
     */
    @Field(type = FieldType.Text)
    private List<String> goodsTags;
    /**
     * 上架的时间
     * 指定时间格式化
     */
    private Date goodsUpTime;
}

9.1.2对文档的操作即数据访问类

@Repository
public interface GoodsDao extends ElasticsearchRepository<Goods, Integer> {

}

9.1.3新增数据

@Autowired
private GoodsDao goodsDao;
@Test
public void testDocumentCurd() throws Exception {
    //新增商品数据100条
    ArrayList<Goods> goods = new ArrayList<>(200);
    for (int i = 1; i <= 100; i++) {
        goods.add(
                new Goods(i,
                        i % 2 == 0 ? "华为电脑" + i : "联想电脑" + i,
                        i % 2 == 0 ? "轻薄笔记本" + i : "游戏笔记本" + i,
                        4999.9 + i,
                        999L,
                        i % 2 == 0 ? "华为续航强" : "联想性能强",
                        i % 2 == 0 ? 1 : 0,
                        666 + i,
                        i % 2 == 0 ? Arrays.asList("小巧", "轻薄", "续航") : Arrays.asList("炫酷", "畅玩", "游戏"),
                        new Date())
        );
    }
    goodsDao.saveAll(goods);
}

9.1.4 修改数据(注意是危险修改)

@Test
public void testUpdate() throws Exception {
    goodsDao.save(new Goods(1, "小米笔记本", null, null, null, null, null, null, null, null));
}

9.1.5删除数据

@Test
public void testDelete() throws  Exception{
    goodsDao.deleteById(1);
}

9.1.6根据Id查询数据

@Test
public void testSearchById() throws Exception {
    Optional<Goods> byId = goodsDao.findById(502);
    System.out.println(byId.get());
}

9.1.7查询所有数据

@Test
public void testSearchAll() throws Exception {
    Iterable<Goods> all = goodsDao.findAll();
    all.forEach(System.out::println);
}

10.复杂的查询操作【重点】

10.1 查询注意点

match:会通过分词器去模糊匹配 例如:华为电脑,会把包含‘华为’,‘电脑’,都查出来
matchPhrase:不分词查询,弥补了match和term
term:精确查找你的关键字,一般使用keywords的约束,使用term
rang:范围查询
match 和 rang 如果同时出现,需要组合bool查询
分页,排序是通用的查询,不需要通过bool组合使用,直接nativeSearchQueryBuilder使用

10.2 查询常用类

QueryBuilders:构造条件对象,例如matchQuery,rangeQuery,boolQuery等
NativeSearchQueryBuilder:组合条件对象,组合后使用build构建查询对象
HighlightBuilder:高亮的查询类,注意使用它的Field静态内部类
FunctionScoreQueryBuilder:权重类,注意它的FilterFunctionBuilder静态内部类

10.3关键字,范围,分页,排序

查询条件:商品名称为“华为",价格在5000-7000之间,按照价格降序排列,输出第一页,每页大小20条

@Test
public void testFuZaSearch() throws Exception {
    //关键字,“华为”
    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("goodsName", "华为");
    //价格范围
    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("goodsPrice").from(5000).to(7000);

    //使用bool组合这两个查询
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(matchQueryBuilder).must(rangeQueryBuilder);

    //创建组合查询器
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
    //去build()构建查询对象
    NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder
            .withQuery(boolQueryBuilder)
            .withPageable(PageRequest.of(0, 20))    //注意范围和分页有关系,可能查出来了,但是当前分页没有
            .withSort(SortBuilders.fieldSort("goodsPrice").order(SortOrder.ASC))
            .build();

    //使用es查询 得到结果集
    SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);
    searchHits.forEach(goodsSearchHit -> {
        //循环结果集,输出
        System.out.println(goodsSearchHit.getContent());
    });
}

10.4高亮查询

查询名称包含“华为“的产品,将"goodsName"设置为高亮字段,添加”字体红色“样式,将查询命中的数据循环,

并将高亮字段的值赋给"goodsName"

    @Test
    public void testHighlight() throws Exception {
        //华为,模糊匹配
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("goodsName", "华为");

        HighlightBuilder.Field goodsName = new HighlightBuilder.Field("goodsName").preTags("<span style='color:red'>").postTags("</span>");

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder
                .withQuery(matchQueryBuilder)
                .withHighlightFields(goodsName)
                .build();
        //得到结果集 我们需要手动组装高亮字段
        SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);

        List<Goods> goodsArrayList = new ArrayList<>();

        searchHits.forEach(goodsSearchHit -> {
            //得到goods对象,但是这里面goodsName属性不是高亮的,所以要改
            Goods goods = goodsSearchHit.getContent();
            List<String> highlightField = goodsSearchHit.getHighlightField("goodsName");
            String highlight = highlightField.get(0);
            //将高亮的商品名称赋给goods对象
            goods.setGoodsName(highlight);
            goodsArrayList.add(goods);
        });
        System.out.println(JSON.toJSONString(goodsArrayList));
    }
}


10.5权重查询

@Test
public void testWeight() throws Exception {
    //根据产品名称和产品介绍进行查询,谁的权重高,排名在前      
    //创建权重数组
    FunctionScoreQueryBuilder.FilterFunctionBuilder[] functionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[2];

    //设置权重
    functionBuilders[0] = (new FunctionScoreQueryBuilder.FilterFunctionBuilder(
            QueryBuilders.matchQuery("goodsName", "华为"),
            ScoreFunctionBuilders.weightFactorFunction(6)//给名称设置10的权重大小
    ));
    functionBuilders[1] = (
            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                    QueryBuilders.matchQuery("goodsBrief", "联想"),
                    ScoreFunctionBuilders.weightFactorFunction(10)//给卖点设置4的权重
            ));

    FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(functionBuilders);

    functionScoreQueryBuilder.setMinScore(2) //设置最小分数
            .scoreMode(FunctionScoreQuery.ScoreMode.FIRST);//设置计分方式

    NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder).build();
    SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);
    searchHits.forEach(goodsSearchHit -> {
        //循环结果集,打印结果
        System.out.println(goodsSearchHit.getContent());
    });
}


11. ES集群(了解)

这里使用windows方式演示集群,Linux上的集群道理一样,修改配置文件即可

可以参考https://my.oschina.net/u/4353003/blog/4333773

11.1创建三个es节点

在这里插入图片描述

11.2 修改配置文件

11.2.1 Node1修改配置文件

进入elasticsearch-7.15.2-node1\config下,修改elasticsearch.yml

# 设置集群名称,集群内所有节点的名称必须一致。
cluster.name: my-esCluster
# 设置节点名称,集群内节点名称必须唯一。
node.name: node1
# 表示该节点会不会作为主节点,true表示会;false表示不会
node.master: true
# 当前节点是否用于存储数据,是:true、否:false
node.data: true
# 索引数据存放的位置
#path.data: /opt/elasticsearch/data
# 日志文件存放的位置
#path.logs: /opt/elasticsearch/logs
# 需求锁住物理内存,是:true、否:false
#bootstrap.memory_lock: true
# 监听地址,用于访问该es
network.host: 0.0.0.0
# es对外提供的http端口,默认 9200
http.port: 9200
# TCP的默认监听端口,默认 9300
transport.tcp.port: 9300
# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)
discovery.zen.minimum_master_nodes: 2
# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"] 
discovery.zen.fd.ping_timeout: 1m
discovery.zen.fd.ping_retries: 5
# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node1", "node2", "node3"]
# 是否支持跨域,是:true,在使用head插件时需要此配置
http.cors.enabled: true
# “*” 表示支持所有域名
http.cors.allow-origin: "*"
action.destructive_requires_name: true
action.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*
xpack.security.enabled: false
xpack.monitoring.enabled: true
xpack.graph.enabled: false
xpack.watcher.enabled: false
xpack.ml.enabled: false

11.2.2 Node2修改配置文件

# 设置集群名称,集群内所有节点的名称必须一致。
cluster.name: my-esCluster
# 设置节点名称,集群内节点名称必须唯一。
node.name: node2
# 表示该节点会不会作为主节点,true表示会;false表示不会
node.master: true
# 当前节点是否用于存储数据,是:true、否:false
node.data: true
# 索引数据存放的位置
#path.data: /opt/elasticsearch/data
# 日志文件存放的位置
#path.logs: /opt/elasticsearch/logs
# 需求锁住物理内存,是:true、否:false
#bootstrap.memory_lock: true
# 监听地址,用于访问该es
network.host: 0.0.0.0
# es对外提供的http端口,默认 9200
http.port: 9201
# TCP的默认监听端口,默认 9300
transport.tcp.port: 9301
# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)
discovery.zen.minimum_master_nodes: 2
# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"] 
discovery.zen.fd.ping_timeout: 1m
discovery.zen.fd.ping_retries: 5
# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node1", "node2", "node3"]
# 是否支持跨域,是:true,在使用head插件时需要此配置
http.cors.enabled: true
# “*” 表示支持所有域名
http.cors.allow-origin: "*"
action.destructive_requires_name: true
action.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*
xpack.security.enabled: false
xpack.monitoring.enabled: true
xpack.graph.enabled: false
xpack.watcher.enabled: false
xpack.ml.enabled: false

11.2.3 Node3修改配置文件

# 设置集群名称,集群内所有节点的名称必须一致。
cluster.name: my-esCluster
# 设置节点名称,集群内节点名称必须唯一。
node.name: node3
# 表示该节点会不会作为主节点,true表示会;false表示不会
node.master: true
# 当前节点是否用于存储数据,是:true、否:false
node.data: true
# 索引数据存放的位置
#path.data: /opt/elasticsearch/data
# 日志文件存放的位置
#path.logs: /opt/elasticsearch/logs
# 需求锁住物理内存,是:true、否:false
#bootstrap.memory_lock: true
# 监听地址,用于访问该es
network.host: 0.0.0.0
# es对外提供的http端口,默认 9200
http.port: 9202
# TCP的默认监听端口,默认 9300
transport.tcp.port: 9302
# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)
discovery.zen.minimum_master_nodes: 2
# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"] 
discovery.zen.fd.ping_timeout: 1m
discovery.zen.fd.ping_retries: 5
# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node1", "node2", "node3"]
# 是否支持跨域,是:true,在使用head插件时需要此配置
http.cors.enabled: true
# “*” 表示支持所有域名
http.cors.allow-origin: "*"
action.destructive_requires_name: true
action.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*
xpack.security.enabled: false
xpack.monitoring.enabled: true
xpack.graph.enabled: false
xpack.watcher.enabled: false
xpack.ml.enabled: false

11.3 启动es

进入bin目录下 逐个启动,三台全部双击启动,注意不要关闭黑窗口

11.4 访问查看集群信息和状态

访问查看:http://127.0.0.1:9200/_cat/nodes

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-POSqzso3-1671947370533)(images\29.png)]

也可以使用head插件查看

在这里插入图片描述

11.5SpringBoot连接ES集群

spring:
    elasticsearch:
        uris:
            - http://127.0.0.1:9200
            - http://127.0.0.1:9201
            - http://127.0.0.1:9202

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

huangshaohui00

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值