jieba分词(1):入门案例

1 场景介绍

大数据量的查询问题

假设我们要从商品的表里面查询一个商品

我们的数据库里面肯定有个t_goods的表,我们现在利用商品的名称做模糊查询

1.1 对于数据库的查询的

select * from t_goods where goodsName like “%手机%” ;

问题:

  1. 这个查询速度快不快?
  2. 对于goodsName 是否添加了索引(假设我们添加了)
  3. 对于上面的sql 语句,是否会走索引?

索引的本质是一颗树,若我们使用(“%手机%” ) 查询时,它无法去比较大小,无法比较,就无法走索引!

那种场景走索引:最左匹配原则 goodsName like “手机%”,它会走索引。

                             goodsName like “%手机” 它不会走索引。

既然不会走索引,它的查询速度,就需要来一个全表的扫描。它的速度会非常慢!

假设我们的数据有百万级别的,查询一个商品,可能就需要20s 左右!

1.2 使用Map 集合来做查询

数据结构如下:Map<String,List<ID>>

我们在Map 集合的Key 放商品的关键字,value放商品的id的集合。

到时我们使用关键字查询商品的ids就可以了

1.3 怎么得到商品的关键字?

商品名称Eg: 

【小米10 旗舰新品2月13日14点发布】小米10 骁龙865 5G 抢先预约抽壕礼

荣耀20S 李现同款 3200万人像超级夜景 4800万超广角AI三摄 麒麟810 全网通版

荣耀20i 3200万AI自拍 超广角三摄 全网通版6GB+64GB 渐变红 移动联通电信4G

Redmi 8A 5000mAh 骁龙八核处理器 AI人脸解锁 4GB+64GB 深海蓝 游戏老人手机

1.4 老师问你一个问题:请说出包含 明月的古诗?

明月几时有,把酒问青天(苏东坡《水调歌头》)

海上升明月,天涯共此时(张九龄《望月怀远》)

暗尘随马去,明月逐人来(苏昧道《正月十五夜》)

三五明月满,四五蟾兔缺(无名氏《孟冬寒气至》)

白云还自散,明月落谁家(李白《忆东山二首》)

明月却多情,随人处处行(张先《菩萨蛮》)

明月净松林,千峰同一色(欧阳修《自菩提步月归广化寺》)

明月几时有,把酒问青天(苏轼《水调歌头》)

明月出天山,茫茫人海间(李白《关山月》)

明月照高楼,流光正徘徊(曹植《怨歌行》)

明月隐高树,长河没晓天(陈子昂《春夜别友人》)

举杯邀明月,对影成三人(李白《月下独酌》)

举头望明月,低头思故乡(李白《静夜思》)

深林人不知,明月来相照(王维《竹里馆》)

明月松间照,清泉石上流(王维《山居秋暝》)

如果在使用数据库查询,你只能遍历你学过的每一首诗,看看里面有没有《明月》两个字

如果使用索引:

明月---List<以上所有>

白云---List<忆东山二首>

青天---List<水调歌头>

2 分词实现操作

新建一个maven项目

2.1 导入jieba分词依赖

<dependencies>
    <dependency>
        <groupId>com.huaban</groupId>
        <artifactId>jieba-analysis</artifactId>
        <version>1.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>

2.2 分词器测试

package com.example.demo;

import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;

import java.util.List;

public class TestJieBa {
    //声明一个分词对象
    private static JiebaSegmenter jiebaSegmenter=new JiebaSegmenter();

    public static void main(String[] args) {

        String content="锤子(smartisan) 坚果Pro3 8GB+128GB 黑色 骁龙855PLUS 4800万四摄 全网通双卡双待 全面屏游戏手机";
        /***
         * @Description:
         * 参数1  要分词的内容
         * 参数1:分词模式
         */
        List<SegToken> tokens = jiebaSegmenter.process(content, JiebaSegmenter.SegMode.SEARCH);

        for (SegToken token : tokens) {
            System.out.println(token.word);
        }
        System.out.println("分词完成"+tokens.size());


    }
}

启动后结果如下:

分词器引入成功。 

3 使用商品搜索案例来展示我们的Map集合

一下模拟商品查询的过程

3.1 商品实体类

package com.example.demo.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
    private Integer id;//商品ID

    private String goodsName;//商品名称

    private Double goodsPrice;//商品价格
}

3.2 数据库工具类

这边只是模拟数据库,没有进行数据库的连接

package com.example.demo.util;

import com.example.demo.domain.Goods;

import java.util.*;

public class DBUtils {
    private static Map<Integer, Goods> db=new HashMap<>();

    public static void insert(Goods goods){
        db.put(goods.getId(),goods);
    }

    public static Goods getById(Integer id){
        return db.get(id);
    }


    /***
     * @Description:
     * @Param: 提供一个根据ids的集合查询商品的方法    key--->多个商品ID
     * @return:
     */
    public static List<Goods> getByIds(Set<Integer> ids){
        if(null==ids||ids.isEmpty()){
            return Collections.emptyList();
        }

        List<Goods> goods=new ArrayList<>();
        for (Integer id : ids) {
            Goods g = db.get(id);
            if(null!=g){
                goods.add(g);
            }

        }
        return goods;
    }
}

3.3 商品服务的接口GoodsService

package com.example.demo.service;

import com.example.demo.domain.Goods;

import java.util.List;

public interface GoodsService {
    /**
     * @Description: 添加商品
     * @Param: [goods]
     * @return: void
     */
    void insert(Goods goods);

    /**
     * @Description: 根据商品名称模糊查询商品
     * @Param: [goodsName]
     * @return: java.util.List<com.leige.solr.test.domain.Goods>
     */
    List<Goods> findByGoodsName(String goodsName);
}

3.4 商品服务的实现类(GoodsServiceImpl)

package com.example.demo.service.Impl;

import com.example.demo.domain.Goods;
import com.example.demo.service.GoodsService;
import com.example.demo.util.DBUtils;
import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;

import java.util.*;

public class GoodsServiceImpl implements GoodsService {
    //模拟一个索引库
    private Map<String, Set<Integer>> indexs=new HashMap<>();

    private JiebaSegmenter jiebaSegmenter=new JiebaSegmenter();

    @Override
    public void insert(Goods goods) {
        /***
         * 我们在插入商品时,要构造一个Map集合
         * Map<String,List<ID>/>
         */
        //分词
        List<String> keywords= this.fenci(goods.getGoodsName());

        //插入数据
        DBUtils.insert(goods);
        //保存到分词的关键字和ids的映射关系
        saveKeyWords(keywords,goods.getId());
    }

    /**
     * @Description: 保存分词和id的关系
     * @Param: [keywords, id]
     * @return: void
     */
    private void saveKeyWords(List<String> keywords, Integer id) {
        if(null!=keywords&&!keywords.isEmpty()){
            for (String keyword : keywords) {
                if(indexs.containsKey(keyword)){//先看关键字在索引里面是否存在
                    Set<Integer> integers = indexs.get(keyword);//得到这个关键字对应该的已存在的ids集合
                    integers.add(id);//把新插入的id放入
                }else{//这是一个新词,之前的索引库不存在
                    HashSet<Integer> ids = new HashSet<>();
                    ids.add(id);
                    indexs.put(keyword,ids);
                }
            }
        }

    }

    /***
     * @Description: 完成分词
     * @Param: [goodsName]
     * @return: java.util.List<java.lang.String>
     */
    private List<String> fenci(String goodsName) {
        List<SegToken> tokens = jiebaSegmenter.process(goodsName, JiebaSegmenter.SegMode.SEARCH);
        List<String> keywords=new ArrayList<>(tokens.size());
        for (SegToken token : tokens) {
            keywords.add(token.word);
        }
        return keywords;
    }

    /***
     * @Description: 查询
     * @Param: [goodsName]
     * @return: java.util.List<com.leige.solr.test.domain.Goods>
     */
    @Override
    public List<Goods> findByGoodsName(String goodsName) {
        //直接从Map里面取有没有
        if(indexs.containsKey(goodsName)){
            Set<Integer> ids = indexs.get(goodsName);//取出有goodsName里面有传过来的goodsName商品的ID
            List<Goods> goodsList = DBUtils.getByIds(ids);
            return goodsList;
        }
        return Collections.emptyList();
    }
}

3.5 测试类

package com.example.demo;

import com.example.demo.domain.Goods;
import com.example.demo.service.GoodsService;
import com.example.demo.service.Impl.GoodsServiceImpl;

import java.util.List;

public class TestApp {
    public static void main(String[] args) {
        GoodsService goodsService = new GoodsServiceImpl();
        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) ;
        goodsService.insert(goods);
        goodsService.insert(goods1);
        goodsService.insert(goods2);
        goodsService.insert(goods3);

        List<Goods> goodss = goodsService.findByGoodsName("红米");
        for (Goods goodsTest : goodss) {
            System.out.println(goodsTest);
        }
    }
}

3.6 搜索结果如下

4 缺陷解决

以上代码我们会发现一个问题,我们在搜索红米手机或者其他手机的全名的时候,搜索不出来结果

原因:

分词器对查询的关键字进行分词的时候,对关键字进行了拆分,没有保留原来的完整关键字,

解决方案:

搜索的时候也进行分词

操作如下:

(1)修改GoodsService

/**
 * @Description: 根据商品名称模糊查询商品
 * @Param: [goodsName]
 * @return: java.util.List<com.leige.solr.test.domain.Goods>
 */
List<Goods> findByKeyWord(String keyword);

(2)修改GoosServiceImpl

@Override
public List<Goods> findByKeyWord(String keyword) {

    //先分词  再查询
    List<String> stringList = this.fenci(keyword);
    Set<Integer> idsSet = new HashSet<>();
    for (String kw : stringList) {
        //直接从Map里面取有没有
        if(indexs.containsKey(kw)){
            Set<Integer> ids = indexs.get(kw);//取出有goodsName里面有传过来的goodsName商品的ID
            idsSet.addAll(ids);
        }
    }

    if(idsSet.isEmpty()){
        return Collections.emptyList();
    }else{
        return DBUtils.getByIds(idsSet);
    }
}

(3)修改测试类

package com.example.demo;

import com.example.demo.domain.Goods;
import com.example.demo.service.GoodsService;
import com.example.demo.service.Impl.GoodsServiceImpl;

import java.util.List;

public class TestApp {
    public static void main(String[] args) {
        GoodsService goodsService = new GoodsServiceImpl();
        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) ;
        goodsService.insert(goods);
        goodsService.insert(goods1);
        goodsService.insert(goods2);
        goodsService.insert(goods3);

        List<Goods> goodss = goodsService.findByKeyWord("红米手机");
        for (Goods goodsTest : goodss) {
            System.out.println(goodsTest);
        }
    }
}

结果如下

3.7 对比直接查询

使用分词器之前:是需要把数据库做一个全表的扫描

使用分词器之后:直接通过计算hash值定位 值,在非常理想的情况下。他的速度,只计算一次

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开关电源基础01:电源变换器基础(2)

说在开头&#xff1a;关于德布罗意的电子波&#xff08;3&#xff09; 1923年&#xff0c;德布罗意在求出他的相波之前&#xff0c;康普顿刚好用光子说解释了康普顿效应&#xff08;记性好的胖友们应该还记得&#xff1a;散射波的波长变长问题&#xff09;&#xff0c;从而带领…

SPSS如何进行聚类分析之案例实训?

文章目录 0.引言1.快速聚类分析2.分层聚类分析3.两阶段聚类分析 0.引言 因科研等多场景需要进行数据统计分析&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;本文对聚类分析进行阐…

[架构之路-187]-《软考-系统分析师》-5-数据库系统 - 操作型数据库OLTP与分析型数据库OLAP比较

OLAP与OLTP的区别&#xff1f; OLTP(Online transaction processing) 在线/联机事务处理。典型的OLTP类操作都比较简单&#xff0c;主要是对数据库中的数据进行增删改查&#xff0c;操作主体一般是产品的用户。 OLAP(Online analytical processing): 指联机分析处理。通过分…

SPSS如何进行判别分析之案例实训?

文章目录 0.引言1.一般判别分析2.逐步判别分析3.决策树分析 0.引言 因科研等多场景需要进行数据统计分析&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;本文对判别分析进行阐述。…

类和对象(上)

文章目录 1.面向过程和面向对象初步认识2.类的引入3.类的定义3.1声明和定义全部放在类体3.2.声明放在.h&#xff0c;定义放在.cpp 4..类的访问限定符及封装4.1封装4.2访问限定符4.3C中的struct和class 5.类的作用域6.类的实例化6.1引入6.2定义 7.类对象模型7.1类对象的存储方式…

MySQL知识学习06(SQL语句在MySQL中的执行过程)

1、MySQL 基本架构概览 下图是 MySQL 的一个简要架构图&#xff0c;从下图可以很清晰的看到用户的 SQL 语句在 MySQL 内部是如何执行的。 先简单介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图 连接器&#xff1a; 身份认证和权限相关(登录 MySQL 的时候)。查询缓…

Java设计模式-代理模式

简介 代理模式是一种结构型设计模式&#xff0c;它可以让我们通过一个代理对象来访问一个真实的目标对象&#xff0c;从而实现对目标对象的功能扩展或保护。代理模式的主要角色有三个&#xff1a; 抽象主题&#xff08;Subject&#xff09;&#xff1a;定义了真实主题和代理主…

【Mybatis】增删改查

1.添加相应的jar包 2.创建持久化类 在src目录下创建一个名为com.mybatis.po的包 创建持久化类MyUser,包含三个属性&#xff08;uid,uname,usex) package com.mybatis.po; /***springtest数据库中user表的持久化类*/ public class MyUser {private Integer uid;//主键private…

OpenGL(六)——坐标系统

目录 一、前言 二、空间系 2.1 局部空间 2.2 世界空间 2.3 观察空间 2.4裁剪空间 2.5 正射投影 2.6 透视投影 2.7 屏幕空间 三、透视箱子 3.1 创建模型矩阵 3.2 创建观察矩阵 3.3 创建透视投影矩阵 3.4 修改顶点着色器 3.5 传递变换矩阵 四、旋转的箱子 五、好…

[Gitops--10]微服务项目部署流水线编写

微服务项目部署流水线编写 1. 部署环境说明 序号管理地址作用1192.168.31.199GitLab2192.168.31.104Harbor3192.168.31.131kubesphere 1.1 GitLab 1.2 流水线 1.2.1 创建流水线 1.2.2 创建凭证 1.2.3 创建kubeconfig凭证 这里需要注意的是,config中如果使用的是域名,那么需…

BetaFlight统一硬件配置文件研读之serial命令

BetaFlight统一硬件配置文件研读之serial命令 1. 源由2. 代码分析3. 实例分析4. 配置情况5. 参考资料 统一硬件配置文件的设计是一种非常好的设计模式&#xff0c;可以将硬件和软件的工作进行解耦。 1. 源由 cli命令中serial是对UART串口的配置&#xff0c;通常情况下BetaFli…

Redo log详解

WAL&#xff08;Write-Ahead Logging&#xff09;机制 WAL 的全称是 Write-Ahead Logging&#xff0c;中文称预写式日志(日志先行)&#xff0c;是一种数据安全写入机制。就是先写日志&#xff0c;然后再写入磁盘&#xff0c;这样既能提高性能又可以保证数据的安全性。Mysql中的…

基于Python的PROSAIL模型介绍以及使用

1、介绍 PROSAIL是两种模型耦合得到的。 SAIL是冠层尺度的辐射传输模型&#xff0c;把冠层假设成是连续的且具有给定几何形状和密度的水平均匀分布的介质层&#xff0c;从而模拟入射辐射与均匀介质之间的相互作用&#xff0c;具体还是挺复杂的。而PROSPECT就是叶片尺度的辐射传…

Kafka知识概况

Kafka知识概况 Kafka简介Kafka 生产者Kafka BrokerKafka 消费者Kafka-Eagle 监控Kafka-Kraft 模式集成 SpringBoot Kafka简介 消息队列简介&#xff1a; 目 前企业中比较常见的消息队列产 品主 要有 Kafka、ActiveMQ 、RabbitMQ 、RocketMQ 等。在大数据场景主要采用 Kafka 作…

vmware虚拟机安装k8s(之前已经安装过docker)

1、安装开始 先执行&#xff1a;curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add 再执行更改源&#xff1a;echo "deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main" >> /etc/apt/sources.list …

redis分布式锁

文章目录 锁的种类一个靠谱分布式锁需要具备的条件和刚需独占性高可用防死锁不乱抢重入性 如何一步一步实现一个完备的分布式锁单机版加锁Redis分布式锁setnx宕机与过期 防死锁防止误删key的问题lua脚本保证原子性 hsetnx 可重入锁简单工厂模式RedisDistributeLockDistributed…

阿里云服务器购买教程(新手入门指南)

阿里云服务器ECS选购指南&#xff0c;阿里云百科分享2023阿里云服务器新手选择流程&#xff0c;选购云服务器有两个入口&#xff0c;一个是选择活动机&#xff0c;只需要选择云服务器地域、系统、带宽即可&#xff1b;另一个是在云服务器页面&#xff0c;自定义选择云服务器配置…

mac下用git客户端生成ssh秘钥并配置到souretree进行使用

一、使用git 生成 ssh 密钥 1、Mac 安装 git 客户端 打开终端&#xff0c;执行命令&#xff1a; $ brew install git2、执行命令 $ git config --global user.name "xxx" 你自己的名字 $ git config --global user.email "xxxxxx.com&q…

深度学习的环境搭建(window+pytorch)

1.检查是否安装CUDA CUDA&#xff08;Compute Unified Device Architecture&#xff09;是由 NVIDIA 推出的一种并行计算平台和编程模型&#xff0c;用于利用 NVIDIA GPU&#xff08;Graphics Processing Unit&#xff09;的强大计算能力进行高性能计算任务。CUDA 的主要特点是…

App违反Google数据安全政策,解决方案

前言 google隐私政策阶段性会进行更新&#xff0c;时长关注隐私政策变化&#xff0c;避免app被强制下架&#xff0c;影响后续运营工作。 邮件内容 摘录邮件详情 我们在以下区域发现了问题&#xff1a; SPLIT_BUNDLE 2:政策声明&#xff0c;数据安全部分&#xff1a;“https:…