Java微服务篇3——Lucene

Java微服务篇3——Lucene

1、数据分类

1.1、结构化数据

具有固定格式或有限长度的数据,如数据库,元数据等

常见的结构化数据也就是数据库中的数据,在数据库中搜索很容易实现,通常都是使用 sql语句进行查询,而且能很快的得到查询结果
在这里插入图片描述

数据库中的数据存储是有规律的,有行有列而且数据格式、数据长度都是固定的,所以搜索很容易

1.2、非结构化数据

不定长或无固定格式的数据,如邮件,word 文档等磁盘上的文件

1.2.1、顺序扫描

顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文 档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,接着看下一个文件,直到扫 描完所有的文件。如利用 windows 的搜索也可以搜索文件内容,只是相当的慢

1.2.2、全文检索

全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在 文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果 反馈给用户的检索方法。这个过程类似于通过字典的目录查字的过程

2、全文检索(Lucene)

Lucene 是 apache 下的一个开放源代码的全文检索引擎工具包。提 供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言),Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。

2.1、Lucene优点

稳定、索引性能高

  • 每小时能够索引150GB以上的数据
  • 对内存的要求小,只需要1MB的堆内存
  • 增量索引和批量索引一样快
  • 索引的大小约为索引文本大小的20%~30%

高效、准确、高性能的搜索算法

  • 良好的搜索排序
  • 强大的查询方式支持:短语查询、通配符查询、临近查询、范围查询等
  • 支持字段搜索(如标题、作者、内容) 可根据任意字段排序
  • 支持多个索引查询结果合并
  • 支持更新操作和查询操作同时进行
  • 支持高亮、join、分组结果功能
  • 速度快
  • 可扩展排序模块,内置包含向量空间模型、BM25模型可选
  • 可配置存储引擎

跨平台

  • 纯java编写
  • 作为Apache开源许可下的开源项目,你可以在商业或开源项目中使用
  • Lucene有多种语言实现版(如C,C++、Python等),不仅仅是JAVA

2.2、架构图

在这里插入图片描述
在这里插入图片描述

2.3、Lucene实现全文检索流程

在这里插入图片描述

2.4、应用场景

单机软件的搜索:word、markdown

站内搜索:京东、淘宝、拉勾,索引源是数据库

搜索引擎:百度、Google,索引源是爬虫程序抓取的数据

3、Lucene实战

3.1、项目搭建

job_info.sql文件 百度云:https://pan.baidu.com/s/1Iw7Hfd4kHSVptDKdQ2bmaQ提取码:m27x

导入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>4.10.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>4.10.3</version>
        </dependency>
    </dependencies>

实体类

public class JobInfo {
    private Long id;
    private String company_name;
    private String company_addr;
    private String company_info;
    private String job_name;
    private String job_addr;
    private String job_info;
    private int salary_min;
    private int salary_max;
    private String url;
    private String time;
}

mapper

@Mapper
public interface JobInfoMapper {
    @Select("select * from job_info")
    public List<JobInfo> selectJobInfo();
}

service

public interface JobInfoService {
    public List<JobInfo> selectJobInfo();
}
@Service
public class JobInfoServiceImpl implements JobInfoService {
    @Autowired
    JobInfoMapper jobInfoMapper;
    @Override
    public List<JobInfo> selectJobInfo() {
        return jobInfoMapper.selectJobInfo();
    }
}

controller

@RestController
public class JobInfoController {
    @Autowired
    JobInfoServiceImpl jobInfoService;
    @RequestMapping("/")
    public String hello(){
        return "hello,lucene!";
    }
    @RequestMapping("/selectJobInfo")
    public List<JobInfo> selectJobInfo(){
        return jobInfoService.selectJobInfo();
    }
}

application.yaml

mybatis:
    type-aliases-package: cn.winkto.bean
    mapper-locations: classpath:mapper/*.xml
spring:
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: blingbling123.
        url: jdbc:mysql://localhost:3306/job?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    application:
        name: product
server:
    port: 8099

启动类

@SpringBootApplication
@MapperScan("cn.winkto.mapper")
public class LuceneApplication {

    public static void main(String[] args) {
        SpringApplication.run(LuceneApplication.class, args);
    }

}

3.2、Filed类型

Field类型数据类型是否分词是否索引是否存储说明
StringField(FieldName, FieldValue, Store.YES)字符串NYY/N字符串类型Field, 不分词, 作为一个整体进行索引(如: 身份证号, 订单编号), 是否需要存储由Store.YES或Store.NO决定
StoredField(FieldName, FieldValue)重载方法, 支持多种类型NNY构建不同类型的Field, 不分词, 不索引, 要存储. (如: 商品图片路径)
TextField(FieldName, FieldValue, Store.NO)文本类型YYY/N文本类型Field, 分词并且索引, 是否需要存储由Store.YES或Store.NO决定

3.3、索引创建

@SpringBootTest
class LuceneApplicationTests {
    @Autowired
    JobInfoServiceImpl jobInfoService;
    @Test
    void contextLoads() throws IOException {
        // 索引文件存储的位置 D:\index
        Directory directory= FSDirectory.open(Paths.get("D:\\index"));
        // 分词器
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
        // 索引创建配置对象
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(standardAnalyzer);
        // 索引创建对象
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        // 删除已有索引
        indexWriter.deleteAll();
        // 元数据查询
        List<JobInfo> jobInfos = jobInfoService.selectJobInfo();
        for (JobInfo jobInfo : jobInfos) {
            // 文档对象 import org.apache.lucene.document.*;
            Document indexableFields = new Document();
            // 添加元数据
            indexableFields.add(new StringField("id", String.valueOf(jobInfo.getId()), Field.Store.YES));
            indexableFields.add(new TextField("companyName", jobInfo.getCompany_name(), Field.Store.YES));
            indexableFields.add(new TextField("companyAddr", jobInfo.getCompany_addr(), Field.Store.YES));
            // 添加文档
            indexWriter.addDocument(indexableFields);
        }
        indexWriter.close();
    }
}

3.4、索引查询

@Test
void contextLoads1() throws IOException {
    // 索引文件存储的位置 D:\index
    Directory directory= FSDirectory.open(Paths.get("D:\\index"));
    DirectoryReader reader = DirectoryReader.open(directory);
    IndexSearcher indexSearcher = new IndexSearcher(reader);
    TermQuery termQuery = new TermQuery(new Term("companyName", "北"));
    TopDocs search = indexSearcher.search(termQuery, 100);
    System.out.println(search.totalHits);
    ScoreDoc[] scoreDocs = search.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        int id=scoreDoc.doc;
        Document doc = indexSearcher.doc(id);
        System.out.println(doc.get("companyName"));
        System.out.println("========================");
    }
}

3.5、中文分词器

导入依赖

<dependency>
    <groupId>com.janeluo</groupId>
    <artifactId>ikanalyzer</artifactId>
    <version>2012_u6</version>
</dependency>

测试类

@SpringBootTest
class LuceneApplicationTests {
    @Autowired
    JobInfoServiceImpl jobInfoService;
    @Test
    void contextLoads() throws IOException {
        // 索引文件存储的位置 D:\index
        Directory directory= FSDirectory.open(new File("D:\\index"));
        // 分词器
        // StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
        IKAnalyzer standardAnalyzer = new IKAnalyzer();
        // 索引创建配置对象
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST,standardAnalyzer);
        // 索引创建对象
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        // 删除已有索引
        indexWriter.deleteAll();
        // 元数据查询
        List<JobInfo> jobInfos = jobInfoService.selectJobInfo();
        for (JobInfo jobInfo : jobInfos) {
            // 文档对象 import org.apache.lucene.document.*;
            Document indexableFields = new Document();
            // 添加元数据
            indexableFields.add(new StringField("id", String.valueOf(jobInfo.getId()), Field.Store.YES));
            indexableFields.add(new TextField("companyName", jobInfo.getCompany_name(), Field.Store.YES));
            indexableFields.add(new TextField("companyAddr", jobInfo.getCompany_addr(), Field.Store.YES));
            // 添加文档
            indexWriter.addDocument(indexableFields);
        }
        indexWriter.close();
    }
    @Test
    void contextLoads1() throws IOException {
        // 索引文件存储的位置 D:\index
        Directory directory= FSDirectory.open(new File("D:\\index"));
        DirectoryReader reader = DirectoryReader.open(directory);
        IndexSearcher indexSearcher = new IndexSearcher(reader);
        TermQuery termQuery = new TermQuery(new Term("companyName", "瓜子"));
        TopDocs search = indexSearcher.search(termQuery, 100);
        System.out.println(search.totalHits);
        ScoreDoc[] scoreDocs = search.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int id=scoreDoc.doc;
            Document doc = indexSearcher.doc(id);
            System.out.println(doc.get("companyName"));
            System.out.println("========================");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

眼眸流转

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

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

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

打赏作者

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

抵扣说明:

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

余额充值