搜索引擎Elasticsearch基础与实践

news2024/12/23 11:00:18

倒排索引

将文档中的内容分词,然后形成词条。记录每条词条与数据的唯一表示如id的对应关系,形成的产物就是倒排索引,如下图:
在这里插入图片描述

ElasticSearch数据的存储和搜索原理

在这里插入图片描述
这里的索引库相当于mysql中的database。一个文档(document)是一个可被索引的基础信息单元。

查询逻辑:根据词条去匹配查询,可以对搜索关键字先分词在查询。es中自动会对词条排序,形成一个树形的结构

ElasticSearch概念

  • ElasticSearch是一个基于Lucene的搜索服务器
  • 是一个分布式、高扩展、高实时的搜索与数据分析引擎
  • 基于RESTfur web接口
  • 流行的企业级搜索引警 Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种
  • ElasticSearch和MySql分工不同,MySQL负责存储数据,ElasticSearch负责搜索数据

应用场景

  • 搜索:海量数据的查询
  • 日志数据分析
  • 实时数据分析

映射(maping)

相当于数据库的表结构,也就是定义不同字段的类型
在这里插入图片描述
简单数据类型
1、字符串

  • text:会分词,不支持聚合
  • keyword:不会分词,将全部内容作为一个词条,支持聚合

2、数值
3、布尔 boolean
4、二进制 .binary
范国类型
integer range, float range, long range, double range, date range

复杂数据类型

  • 数组:[]
  • 对象:()

文档操作

添加文档,指定id
put 索引/_doc/id{添加内容}

添加文档,不指定id
post 索引/_doc{添加内容}

查询指定id的文档
get 索引/_doc/id

查询所有文档
get 索引/_doc/_search

IK分词器

java开发的轻量级的中文分词器

springboot整合es

1、引入es的RestHighLevelClient依赖:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

2、初始化RestHighLevelClient:
在这里插入图片描述
导入client

@Autowiredprivate 
RestHighLevelClient client;

索引操作

操作索引对象的对象是indicesClient,使用create函数
参数:
Createindexrequest、请求类型
获取为getIndexrequest
删除为Deleteindexrequest
在这里插入图片描述也可以添加mapping在这里插入图片描述

文档操作

获取操作文档的对象:indexrequest
添加需要在indexrequest中设定索引、id、以及添加的数据(JSON)
修改:indexrequest
查询:getrequest
在这里插入图片描述
在这里插入图片描述

Bulk批量操作

在这里插入图片描述

Elient.bulk(bulkRequest , RequestOptions.DEFAULT);

解释:
1、创建mybatis的map映射,并创建实例对象接收
2、查询mysql数据、存入到对象中
3、创建bulkrequest对象,操作批量操作
4、遍历查询结果,对不符合es映射规定的字段格式的进行转换、并添加到indexrequest中,在添加到bulkrequest中
6、调用client的bulk操作,批量插入

模糊查询

1、wildcard查询:会对查询条件进行分词。还可以使用通配符?(任意单个字符)和 * (0个或多个字符)
2、prefix查询:前缀查询

# wildcard 查询。查询条件分词,模糊查询
GET goods/_search
	"query":(
		"wildcard":{
			"title":
				"value":"华?

在这里插入图片描述
java代码:
在这里插入图片描述

前缀查询;

在这里插入图片描述

范围查询

在这里插入图片描述java代码:
同样只需要修改query这个参数信息就行
在这里插入图片描述

布尔查询

脚本:
boolQuery:对多个查询条件连接。连接方式:
must (and):条件必须成立
must not (not):条件必须不成立
should (or):条件可以成立
filter: 条件必须成立,性能比must高。不会计算得分
在这里插入图片描述

高亮查询

高亮的三要素:
高亮字段、前缀、后缀
在这里插入图片描述
java代码:
1、设置高亮

//设置高亮
HighlightBuilder highlighter = new HighlightBuilder()://
设置三要素
highlighter.field("title");
highlighter.preTags("<font color='red'>");
highlighter.postTags("</font>");

2、用高亮的结果代替原有的结果

// 获取高亮结果,替换goods中的title
Map<String,HighlightField> highlightFields = hit,getHighlightFields().
HighlightField HighlightField = highlightFields.get("title");
Text[] fragments = HighlightField.fragments();//这里的fragments是表示我们的拿到是一个一个的高亮片段,包含了不同区域的高亮
//替换goods.setTitle(fragments[e].tostring()):

第二步为从查询到hit中的hightlight代替原有的字段

2、黑马头条es实践

2.1)搭建搜索微服务

(1)导入 heima-leadnews-search
(2)在heima-leadnews-service的pom中添加依赖

<!--elasticsearch-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.4.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.4.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.4.0</version>
</dependency>

(3)nacos配置中心leadnews-search

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
elasticsearch:
  host: 192.168.200.130
  port: 9200
2.2) 搜索接口定义
package com.heima.search.controller.v1;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.search.dtos.UserSearchDto;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
@RequestMapping("/api/v1/article/search")
public class ArticleSearchController {


    @PostMapping("/search")
    public ResponseResult search(@RequestBody UserSearchDto dto) throws IOException {
        return null;
    }
}

UserSearchDto

package com.heima.model.search.dtos;

import lombok.Data;

import java.util.Date;


@Data
public class UserSearchDto {

    /**
    * 搜索关键字
    */
    String searchWords;
    /**
    * 当前页
    */
    int pageNum;
    /**
    * 分页条数
    */
    int pageSize;
    /**
    * 最小时间
    */
    Date minBehotTime;

    public int getFromIndex(){
        if(this.pageNum<1)return 0;
        if(this.pageSize<1) this.pageSize = 10;
        return this.pageSize * (pageNum-1);
    }
}
2.3) 业务层实现

创建业务层接口:ApArticleSearchService

package com.heima.search.service;

import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.common.dtos.ResponseResult;

import java.io.IOException;

public interface ArticleSearchService {

    /**
     ES文章分页搜索
     @return
     */
    ResponseResult search(UserSearchDto userSearchDto) throws IOException;
}

实现类:

package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * es文章分页检索
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {

        //1.检查参数
        if(dto == null || StringUtils.isBlank(dto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.设置查询条件
        SearchRequest searchRequest = new SearchRequest("app_info_article");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //关键字的分词之后查询
        QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
        boolQueryBuilder.must(queryStringQueryBuilder);

        //查询小于mindate的数据
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
        boolQueryBuilder.filter(rangeQueryBuilder);

        //分页查询
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(dto.getPageSize());

        //按照发布时间倒序查询
        searchSourceBuilder.sort("publishTime", SortOrder.DESC);

        //设置高亮  title
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
        highlightBuilder.postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);


        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);


        //3.结果封装返回

        List<Map> list = new ArrayList<>();

        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            Map map = JSON.parseObject(json, Map.class);
            //处理高亮
            if(hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0){
                Text[] titles = hit.getHighlightFields().get("title").getFragments();
                String title = StringUtils.join(titles);
                //高亮标题
                map.put("h_title",title);
            }else {
                //原始标题
                map.put("h_title",map.get("title"));
            }
            list.add(map);
        }

        return ResponseResult.okResult(list);

    }
}
2.4) 控制层实现

新建控制器ArticleSearchController

package com.heima.search.controller.v1;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.service.ArticleSearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
@RequestMapping("/api/v1/article/search")
public class ArticleSearchController {

    @Autowired
    private ArticleSearchService articleSearchService;

    @PostMapping("/search")
    public ResponseResult search(@RequestBody UserSearchDto dto) throws IOException {
        return articleSearchService.search(dto);
    }
}
3.5.5) 测试

需要在app的网关中添加搜索微服务的路由配置

#搜索微服务
- id: leadnews-search
 uri: lb://leadnews-search
 predicates:
   - Path=/search/**
 filters:
   - StripPrefix= 1

新增文章同步添加索引

在这里插入图片描述
1、把SearchArticleVo放到model工程下
2、文章微服务的ArticleFreemarkerService中的buildArticleToMinIO方法中收集数据并发送消息

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    /**
     * 送消息,创建索引
     * @param apArticle
     * @param content
     * @param path
     */
    private void createArticleESIndex(ApArticle apArticle, String content, String path) {
        SearchArticleVo vo = new SearchArticleVo();
        BeanUtils.copyProperties(apArticle,vo);
        vo.setContent(content);
        vo.setStaticUrl(path);

        kafkaTemplate.send(ArticleConstants.ARTICLE_ES_SYNC_TOPIC, JSON.toJSONString(vo));
    }

3、文章微服务集成kafka发送消息

kafka:
    bootstrap-servers: 192.168.200.130:9092
    producer:
      retries: 10
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

4、搜索微服务中添加kafka的配置,nacos配置如下

spring:
  kafka:
    bootstrap-servers: 192.168.200.130:9092
    consumer:
      group-id: ${spring.application.name}
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

5.定义监听接收消息,保存索引数据

@Component
@Slf4j
public class SyncArticleListener {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @KafkaListener(topics = ArticleConstants.ARTICLE_ES_SYNC_TOPIC)
    public void onMessage(String message){
        if(StringUtils.isNotBlank(message)){

            log.info("SyncArticleListener,message={}",message);

            SearchArticleVo searchArticleVo = JSON.parseObject(message, SearchArticleVo.class);
            IndexRequest indexRequest = new IndexRequest("app_info_article");
            indexRequest.id(searchArticleVo.getId().toString());
            indexRequest.source(message, XContentType.JSON);
            try {
                restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
                log.error("sync es error={}",e);
            }
        }

    }

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

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

相关文章

大语言模型(LLM)综述(七):大语言模型设计应用与未来方向

A Survey of Large Language Models 前言8 A PRACTICAL GUIDEBOOK OF PROMPT DESIGN8.1 提示创建8.2 结果与分析 9 APPLICATIONS10 CONCLUSION AND FUTURE DIRECTIONS 前言 随着人工智能和机器学习领域的迅速发展&#xff0c;语言模型已经从简单的词袋模型&#xff08;Bag-of-…

Mabitys总结

一、ORM ORM(Object/Relation Mapping)&#xff0c;中文名称&#xff1a;对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。 使用JDBC技术时&#xff0c;手动实现ORM映射&#xff1a; 使用ORM时&#xff0c;自动关系映射&#xff1a; &am…

【JavaEE】HTTP协议(什么是HTTP?、HTTP格式、form表单和ajax构造HTTP)

一、什么是HTTP协议&#xff1f; 1.1 HTTP (全称为 “超文本传输协议”) 是一种应用非常广泛的 应用层协议 1.2 理解HTTP协议的工作过程 当我们在浏览器中输入一个 “网址”, 此时浏览器就会给对应的服务器发送一个 HTTP 请求. 对方服务器收到这个请求之后, 经过计算处理, 就…

FMCW雷达论文速览 | TRS 2023, 基于FMCW雷达的多天线高精度测距算法及性能分析

注1:本文系“最新论文速览”系列之一,致力于简洁清晰地介绍、解读最新的顶会/顶刊论文 TRS 2023 | High Accuracy Multi-antenna Ranging Algorithm and Performance Analysis for FMCW Radar 论文原文:https://ieeexplore.ieee.org/document/10309162 Z. Xu, S. Qi and P. Zh…

Python教程之Python中文件路径

文章目录 前言一、Python中文件路径1.绝对路径和相对路径2.目录中的斜杠们3.正则表达式中的斜杠们 二、什么是文件路径&#xff0c;Python中如何书写文件路径&#xff1f;1.Windows上的反斜杠以及OS X和Linux上的正斜杠关于Python技术储备一、Python所有方向的学习路线二、Pyth…

MS90C385B:+3.3V 150MHz 的 24bit 平板显示器(FPD) LVDS 信号发送器

MS90C385B 芯片能够将 28bit 的 TTL 数据转换成 4 通道的低压差分 信号 (LVDS) 。时钟通道经过锁相之后&#xff0c;与数据通道并行输出。当时钟频 率为 150MHz 时&#xff0c; 24bit 的 RGB 数据、 3bit 的 LCD 时序数据和 1bit 的控 制数据以 1050Mbps…

Hadoop常见问题

报错1 &#xff1a;is group-writable, and the group is not root. Its permissions are 0775, datanode启动时&#xff0c;日志报错 1.“xxxx” is group-writable, and the group is not root. Its permissions are 0775, and it is owned by gid 3245. Please fix this…

asp.net core mvc之路由

一、默认路由 &#xff08;Startup.cs文件&#xff09; routes.MapRoute(name: "default",template: "{controllerHome}/{actionIndex}/{id?}" ); 默认访问可以匹配到 https://localhost:44302/home/index/1 https://localhost:44302/home/index https:…

直击第一届中国测绘地理信息大会,华测导航强势出圈!

11月8日&#xff0c;由自然资源部指导&#xff0c;中国测绘学会、中国地理信息产业协会和中国卫星导航定位协会共同主办的第一届中国测绘地理信息大会于浙江德清盛大开幕&#xff0c;各家科研院所、企事业单位云集现场&#xff0c;展示科技创新成果。华测导航携多类智能装备及解…

初步了解OSG智能指针

OSG定义了智能指针模板类ref_ptr<>。 osg命名空间的Referenced类实现了对内存区段的引用计数器功能。 所有的osg节点和场景图形数据&#xff0c;均派生自Referenced类。 ref_ptr<>用于实现一个指向Referenced对象的智能指针。 #include <Geode> #include <…

水泵机组如何通过设备健康管理系统实现预测性维护

水泵机组是关键的工业设备&#xff0c;在正常运行过程中可能遭遇各种故障&#xff0c;影响生产效率和设备寿命。为了提高水泵机组的可靠性和效率&#xff0c;预测性维护成为一种重要的管理方法。本文将介绍水泵机组的结构及常见故障&#xff0c;并详细阐述如何使用设备健康管理…

使用遗传算法优化BP神经网络实现非线性函数拟合

大家好&#xff0c;我是带我去滑雪&#xff01; 非线性函数拟合是一种用于找到与给定数据点集合最好匹配的非线性函数的过程。非线性函数拟合通常用于以下情况&#xff1a; 数据趋势不是线性的&#xff1a;当数据点之间的关系不能用线性方程来表示时&#xff0c;需要使用非线性…

【吞噬星空】斩杀两大兽皇,罗峰实力暴涨,雷神已不是对手

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 深度爆料&#xff0c;《吞噬星空》国漫第92话新剧情解析&#xff0c;罗峰、洪和雷神&#xff0c;已成为师兄弟&#xff0c;但洪和雷神无论在实力还是地位上都高于罗峰。因此&#xff0c;罗峰在这三人中始终担…

【C/PTA】循环结构进阶练习(三)

本文结合PTA专项练习带领读者掌握循环结构&#xff0c;刷题为主注释为辅&#xff0c;在代码中理解思路&#xff0c;其它不做过多叙述。 文章目录 7-1 循环-Fibonacci数列的运算7-2 循环-找数字7-3 循环-小智的捕食计划7-4 循环-抱大腿7-5 循环-跳&#xff01;7-6 循环-生气的峰…

金融帝国实验室(Capitalism Lab)推出一个密钥即完成注册机制!

为了方便趸购『金融帝国实验室』&#xff08;Capitalism Lab&#xff09;正版玩家&#xff0c;Enlight官方正式推出『一个密钥即完成注册』机制&#xff0c;切实简化游戏账户注册流程&#xff01; ————————————— 『一个密钥即完成注册』适用于趸购“游戏本体4DLC”…

前端工程化(vue脚手架安装)

用命令行安装&#xff0c;先安装NodeJs&#xff0c;配置环境变量 1.npm config set prefix "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Node.js" //引号内路径是NodeJs安装所在路径 2.npm config get prefix 查看其是否成功 3.npm install -g vue/cli 4…

Flutter——最详细(AppBar)使用教程

AppBar简介 Material Design 应用栏(标题栏) 使用场景&#xff1a; 顶部标题栏包括一些常用的菜单按钮 属性作用leading左边工具视图automaticallyImplyLeading左边图标的颜色title标题视图actions右边菜单按钮flexibleSpace其高度将与应用栏的整体高度相同bottom左侧底部文本内…

程序员怎样才能学好算法?这本书送几本给大家!

目录 笔者对算法的理解 写书的初衷及过程 本书的内容 购买方式 数据结构和算法是计算机科学的基石&#xff0c;是计算机的灵魂&#xff0c;要想成为计算机专业人员&#xff0c;学习和掌握算法是十分必要的。不懂数据结构和算法的人不可能写出效率更高的代码。计算机科学的很…

【原理篇】二、Bean加载控制

文章目录 1、编程式Bean加载控制2、注解式Bean加载控制3、Conditional派生注解4、Bean依赖的属性配置 Bean的加载控制指根据特定情况对bean进行选择性加载以达到适用于项目的目标 上篇Bean声明的方式中&#xff0c;后4种可以实现对Bean加载的控制&#xff0c;分别是&#xff1a…

0.1+0.2为什么不等于0.3

目录 一、0.10.2是如何执行的&#xff1f;1、转成浮点数2、浮点数相加3、浮点数转成十进制 二、BigDecimal 大家好&#xff0c;我是哪吒。 最近碰到一个问题&#xff0c;很有趣&#xff0c;我就不贴代码了&#xff0c;要不你们会以为我在无中生有。 我现在的心情很复杂&#x…