袁庭新老師ES系列04節(jié)|Lucene實(shí)戰(zhàn)
前言
本節(jié)袁老師將帶領(lǐng)大家學(xué)習(xí)Lucene技術(shù)。Lucene是apache下的一個(gè)開(kāi)源的全文檢索引擎工具包。接下來(lái)帶領(lǐng)大家進(jìn)行Lucene編程的實(shí)戰(zhàn)。你準(zhǔn)備好了嘛?
一. 需求說(shuō)明
生成職位信息索引庫(kù),從索引庫(kù)檢索數(shù)據(jù)。例如我們?cè)谡衅妇W(wǎng)站進(jìn)行職位搜索。

二. 準(zhǔn)備開(kāi)發(fā)環(huán)境
1.準(zhǔn)備數(shù)據(jù)
1.1 運(yùn)行sql腳本
1.通過(guò)Navicat Premium軟件運(yùn)行課前資料中的job_info.sql腳本。完成初始化數(shù)據(jù)的準(zhǔn)備工作。
2.在Navicat Premium工具中的MySQL數(shù)據(jù)庫(kù)【連接名】上右鍵,選擇【運(yùn)行SQL文件...】選項(xiàng),然后后運(yùn)行job_info.sql文件。
3.數(shù)據(jù)庫(kù)腳本文件job_info.sql中的內(nèi)容見(jiàn)下。
CREATE DATABASE `es_db` CHARACTER SET utf8mb4; USE `es_db`; CREATE TABLE `job_info` ( ?`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵 id', ?`company_name` varchar(100) DEFAULT NULL COMMENT '公司名稱', ?`company_addr` varchar(200) DEFAULT NULL COMMENT '公司聯(lián)系方式', ?`company_info` mediumtext DEFAULT NULL COMMENT '公司信息', ?`job_name` varchar(100) DEFAULT NULL COMMENT '職位名稱', ?`job_addr` varchar(50) DEFAULT NULL COMMENT '工作地點(diǎn)', ?`job_info` mediumtext DEFAULT NULL COMMENT '職位信息', ?`salary_min` int(10) DEFAULT NULL COMMENT '薪資范圍,最小', ?`salary_max` int(10) DEFAULT NULL COMMENT '薪資范圍,最大', ?`url` varchar(150) DEFAULT NULL COMMENT '招聘信息詳情頁(yè)', ?`time` varchar(10) DEFAULT NULL COMMENT '職位最近發(fā)布時(shí)間', ?PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7656 DEFAULT CHARSET=utf8mb3 COMMENT='招聘信息'; INSERT INTO `job_info` (`id`, `company_name`, `company_addr`, `company_info`, `job_name`, `job_addr`, `job_info`, `salary_min`, `salary_max`, `url`, `time`) VALUES (1397, '北京中認(rèn)環(huán)宇信息安全技術(shù)有限公司', '北京市豐臺(tái)區(qū)南四環(huán)西路188號(hào)9區(qū)8號(hào)樓', '北京中認(rèn)環(huán)宇信息安全技術(shù)有限公司(簡(jiǎn)稱CQCCA)是由中國(guó)質(zhì)量認(rèn)證中心投資...', ' JAVA軟件開(kāi)發(fā)程師 (職位編號(hào):002)', '北京-豐臺(tái)區(qū)', '參與產(chǎn)品需求分析、系統(tǒng)設(shè)計(jì)工作...', 120000, 180000, 'https://jobs.51job.com/beijing-ftq/101555054.html?s=01&t=5', '2022-02-26'); # 后面省略10000+條INSERT插入語(yǔ)句
1.2 潛在異常
如果在運(yùn)行job_info.sql腳本時(shí)提示1153 - Got a packet bigger than 'max_allowed_packet' bytes出錯(cuò),解決方案見(jiàn)下:
1.查看max_allowed_packet變量默認(rèn)值。原因是我安裝的MySQL的默認(rèn)配置為16MB,而導(dǎo)入的文件數(shù)據(jù)大于默認(rèn)配置所以出錯(cuò)。
# 16777216 / 1024 / 1024 = 16M SHOW VARIABLES LIKE '%max_allowed_packet%';
2.修改max_allowed_packet變量的默認(rèn)值。需要重啟Navicat Premium軟件。
# 設(shè)置成512M SET GLOBAL max_allowed_packet = 524288000;
3.再次使用Navicat Premium軟件運(yùn)行job_info.sql腳本。便可執(zhí)行成功。
2.項(xiàng)目搭建
1.創(chuàng)建一個(gè)Spring Initializr類型的Spring Boot項(xiàng)目,項(xiàng)目的名稱設(shè)置為【lucene-demo】。

2.在項(xiàng)目的pom.xml文件中引入相關(guān)的依賴。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ? ? ? ? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ? ?<modelVersion>4.0.0</modelVersion> ? ? ?<parent> ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ?<artifactId>spring-boot-starter-parent</artifactId> ? ? ? ?<version>2.7.6</version> ? ? ? ?<relativePath/> <!-- lookup parent from repository --> ? ?</parent> ? ? ?<groupId>com.yx</groupId> ? ?<artifactId>lucene-demo</artifactId> ? ?<version>0.0.1-SNAPSHOT</version> ? ?<name>lucene-demo</name> ? ?<description>lucene-demo</description> ? ? ?<properties> ? ? ? ?<java.version>11</java.version> ? ?</properties> ? ? ?<dependencies> ? ? ? ?<!-- Web依賴 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ? ?<artifactId>spring-boot-starter-web</artifactId> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- MySQL驅(qū)動(dòng) --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>com.mysql</groupId> ? ? ? ? ? ?<artifactId>mysql-connector-j</artifactId> ? ? ? ? ? ?<scope>runtime</scope> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- Mybatis-Plus --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>com.baomidou</groupId> ? ? ? ? ? ?<artifactId>mybatis-plus-boot-starter</artifactId> ? ? ? ? ? ?<version>3.5.2</version> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- 引入Lucene核心包及分詞器包 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.apache.lucene</groupId> ? ? ? ? ? ?<artifactId>lucene-core</artifactId> ? ? ? ? ? ?<version>4.10.3</version> ? ? ? ?</dependency> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.apache.lucene</groupId> ? ? ? ? ? ?<artifactId>lucene-analyzers-common</artifactId> ? ? ? ? ? ?<version>4.10.3</version> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- 單元測(cè)試 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ? ?<artifactId>spring-boot-starter-test</artifactId> ? ? ? ? ? ?<scope>test</scope> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- 熱部署 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ? ?<artifactId>spring-boot-devtools</artifactId> ? ? ? ? ? ?<scope>runtime</scope> ? ? ? ? ? ?<optional>true</optional> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- Lombok工具 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>org.projectlombok</groupId> ? ? ? ? ? ?<artifactId>lombok</artifactId> ? ? ? ? ? ?<optional>true</optional> ? ? ? ?</dependency> ? ? ? ? ? ? ?<!-- IK中文分詞器 --> ? ? ? ?<dependency> ? ? ? ? ? ?<groupId>com.janeluo</groupId> ? ? ? ? ? ?<artifactId>ikanalyzer</artifactId> ? ? ? ? ? ?<version>2012_u6</version> ? ? ? ?</dependency> ? ?</dependencies> ? ?<build> ? ? ? ?<plugins> ? ? ? ? ? ?<!-- 打包插件 --> ? ? ? ? ? ?<plugin> ? ? ? ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ? ? ? ?<artifactId>spring-boot-maven-plugin</artifactId> ? ? ? ? ? ? ? ?<configuration> ? ? ? ? ? ? ? ? ? ?<excludes> ? ? ? ? ? ? ? ? ? ? ? ?<exclude> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<groupId>org.projectlombok</groupId> ? ? ? ? ? ? ? ? ? ? ? ? ? ?<artifactId>lombok</artifactId> ? ? ? ? ? ? ? ? ? ? ? ?</exclude> ? ? ? ? ? ? ? ? ? ?</excludes> ? ? ? ? ? ? ? ?</configuration> ? ? ? ? ? ?</plugin> ? ? ? ? ? ? ? ? ? ? ?<!-- 編譯插件 --> ? ? ? ? ? ?<plugin> ? ? ? ? ? ? ? ?<groupId>org.apache.maven.plugins</groupId> ? ? ? ? ? ? ? ?<artifactId>maven-compiler-plugin</artifactId> ? ? ? ? ? ? ? ?<configuration> ? ? ? ? ? ? ? ? ? ?<source>11</source> ? ? ? ? ? ? ? ? ? ?<target>11</target> ? ? ? ? ? ? ? ? ? ?<encoding>utf-8</encoding> ? ? ? ? ? ? ? ?</configuration> ? ? ? ? ? ?</plugin> ? ? ? ?</plugins> ? ?</build> </project>
3.將項(xiàng)目自動(dòng)生成的application.properties文件后綴改為yml類型。并添加數(shù)據(jù)庫(kù)連接配置。
server: ?port: 9000 Spring: ?application: ? ?name: yx-lucene ?datasource: ? ?driver-class-name: com.mysql.cj.jdbc.Driver ? ?url: jdbc:mysql://localhost:3306/es_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC ? ?username: root ? ?password: 123456 # 開(kāi)啟駝峰命名匹配映射 mybatis: ?configuration: ? ?map-underscore-to-camel-case: true
4.搭建項(xiàng)目的MVC分層結(jié)構(gòu)。在com.yx包下創(chuàng)建:pojo包、mapper包、service包、service.impl包、controller包。
3.查詢接口開(kāi)發(fā)
1.在com.yx.pojo包下創(chuàng)建JobInfo實(shí)體類。
package com.yx.pojo; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data @TableName("job_info") public class JobInfo { ? ?@TableId(type = IdType.AUTO) ? ?private Long id; // id屬性建議使用包裝類定義 ? ?private String companyName; ? ?private String companyAddr; ? ?private String companyInfo; ? ?private String jobName; ? ?private String jobAddr; ? ?private String jobInfo; ? ?private int salaryMin; ? ?private int salaryMax; ? ?private String url; ? ?private String time; }
說(shuō)明:SpringBoot項(xiàng)目啟動(dòng)提示This primary key of "id" is primitive !不建議如此請(qǐng)使用包裝類in Class: "com.yx.pojo.JobInfo"。
1.解決方法:使用包裝類替換基本數(shù)據(jù)類型。將id字段封裝成Long類型或Integer類型,具體選擇什么類型取決于數(shù)據(jù)庫(kù)中該id字段的類型。
2.警告原因:如果用long的話id的默認(rèn)值會(huì)是0,會(huì)出現(xiàn)一些問(wèn)題,比如在MyBatis-Plus使用save()方法時(shí)就不能使用算法生成id了,這樣會(huì)生成id為0的數(shù)據(jù),如果有唯一或者主鍵約束的話,下一次生成就會(huì)報(bào)錯(cuò)。
2.在com.yx.mapper包下創(chuàng)建JobInfoMapper接口并繼承MyBatis-Plus提供的BaseMapper<JobInfo>
接口。
package com.yx.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yx.pojo.JobInfo; public interface JobInfoMapper extends BaseMapper<JobInfo> { }
3.在LuceneDemoApplication啟動(dòng)類上添加@MapperScan注解包掃描。
package com.yx; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.yx.mapper") public class LuceneDemoApplication { ? ?public static void main(String[] args) { ? ? ? ?SpringApplication.run(LuceneDemoApplication.class, args); ? ?} }
4.在com.yx.service包下創(chuàng)建JobInfoService接口。
package com.yx.service; import com.yx.pojo.JobInfo; import java.util.List; public interface JobInfoService { ? ?JobInfo selectById(Long id); ? ? ? ?List<JobInfo> selectAll(); }
5.在com.yx.service.impl包下創(chuàng)建JobInfoServiceImpl實(shí)現(xiàn)類。
package com.yx.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yx.mapper.JobInfoMapper; import com.yx.pojo.JobInfo; import com.yx.service.JobInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class JobInfoServiceImpl implements JobInfoService { ? ?@Autowired ? ?private JobInfoMapper jobInfoMapper; ? ?@Override ? ?public JobInfo selectById(Long id) { ? ? ? ?return jobInfoMapper.selectById(id); ? ?} ? ?@Override ? ?public List<JobInfo> selectAll() { ? ? ? ?QueryWrapper<JobInfo> queryWrapper = new QueryWrapper(); ? ? ? ?return jobInfoMapper.selectList(queryWrapper); ? ?} }
6.在com.yx.controller包下創(chuàng)建JobInfoController類。
package com.yx.controller; import com.yx.pojo.JobInfo; import com.yx.service.JobInfoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("job-info") public class JobInfoController { ?@Autowired ?private JobInfoService jobInfoService; ?@RequestMapping("query/{id}") ?public JobInfo getJobInfoById(@PathVariable Long id) { ? ?return jobInfoService.selectById(id); ?} ?@RequestMapping("query") ?public List<JobInfo> getJobInfos() { ? ?return jobInfoService.selectAll(); ?} }
7.運(yùn)行項(xiàng)目主類LuceneDemoApplication,使用ApiPost工具進(jìn)行以下兩個(gè)接口的測(cè)試。
http://localhost:9000/job-info/query http://localhost:9000/job-info/query/1397
三. 創(chuàng)建索引
1.創(chuàng)建索引實(shí)現(xiàn)
在test下創(chuàng)建com.yx.lucene包,并在該包下創(chuàng)建LuceneTests測(cè)試類,并添加創(chuàng)建索引的createIndex()方法。
package com.yx.lucene; import com.yx.pojo.JobInfo; import com.yx.service.JobInfoService; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.*; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.File; import java.io.IOException; import java.util.List; @SpringBootTest public class LuceneTests { ?@Autowired ?private JobInfoService jobInfoService; ?@Test ?public void createIndex() throws IOException { ? ?// 1.指定索引文件存儲(chǔ)的位置 ? ?Directory directory = FSDirectory.open(new File("/Users/yuanxin/Documents/lucene/index")); ? ? ? ?// 2.配置版本和分詞器 ? ?Analyzer analyzer = new StandardAnalyzer(); // 標(biāo)準(zhǔn)分詞器 ? ?IndexWriterConfig config = new IndexWriterConfig(Version.LATEST,analyzer); ? ? ? ?// 3.創(chuàng)建一個(gè)用來(lái)創(chuàng)建索引的對(duì)象IndexWriter ? ?IndexWriter indexWriter = new IndexWriter(directory,config); ? ?indexWriter.deleteAll(); // 先刪除索引 ? ? ? ?// 4.獲取原始數(shù)據(jù) ? ?List<JobInfo> jobInfoList = jobInfoService.selectAll(); ? ? ? ?// 有多少的數(shù)據(jù)就應(yīng)該構(gòu)建多少lucene的文檔對(duì)象document ? ?for (JobInfo jobInfo : jobInfoList) { ? ? ?Document document = new Document(); ? ? ? ? ?// 域名、值、源數(shù)據(jù)是否存儲(chǔ) ? ? ?document.add(new LongField("id", jobInfo.getId(), Field.Store.YES)); ? ? ?document.add(new TextField("companyName", jobInfo.getCompanyName(), Field.Store.YES)); ? ? ?document.add(new TextField("companyAddr", jobInfo.getCompanyAddr(), Field.Store.YES)); ? ? ?document.add(new TextField("companyInfo", jobInfo.getCompanyInfo(), Field.Store.YES)); ? ? ?document.add(new TextField("jobName", jobInfo.getJobName(), Field.Store.YES)); ? ? ?document.add(new TextField("jobAddr", jobInfo.getJobAddr(), Field.Store.YES)); ? ? ?document.add(new TextField("jobInfo", jobInfo.getJobInfo(), Field.Store.YES)); ? ? ?document.add(new IntField("salaryMin", jobInfo.getSalaryMin(), Field.Store.YES)); ? ? ?document.add(new IntField("salaryMax", jobInfo.getSalaryMax(), Field.Store.YES)); ? ? ?document.add(new StringField("url", jobInfo.getUrl(), Field.Store.YES)); ? ? ?document.add(new StringField("time", jobInfo.getTime(), Field.Store.YES)); ? ? ? ? ? ?// StringField不需要分詞時(shí)使用,舉例:url、電話號(hào)碼、身份證號(hào) ? ? ?indexWriter.addDocument(document); ? ?} ? ? ? ?// 關(guān)閉資源 ? ?indexWriter.close(); ?} }
2.索引解析
2.1 Index索引
在Lucene中一個(gè)索引是存放在一個(gè)文件夾中的。如下圖所示。同一文件夾中的所有的文件構(gòu)成一個(gè)Lucene索引。

2.2 Segment段
按層次保存了索引到詞的包含關(guān)系:索引(Index) => 段(segment) => 文檔(Document) => 域(Field) => 詞(Term)。
即此索引包含了哪些段,每個(gè)段包含了哪些文檔,每個(gè)文檔包含了哪些域,每個(gè)域包含了哪些詞。
一個(gè)索引可以包含多個(gè)段,段與段之間是獨(dú)立的,添加新文檔可以生成新的段,不同的段可以合并。
如上圖中,具有相同前綴文件的屬同一個(gè)段,圖中共一個(gè)段(以"_0"開(kāi)頭的文件)。
segments_1和segments.gen是段的元數(shù)據(jù)文件,也即它們保存了段的屬性信息。
2.3 Field的特性
Document(文檔)是Field(域)的承載體,一個(gè)Document由多個(gè)Field組成。Field由名稱和值兩部分組成,F(xiàn)ield的值是要索引的內(nèi)容,也是要搜索的內(nèi)容。
是否分詞(tokenized):
是:將Field的值進(jìn)行分詞處理,分詞的目的是為了索引。如:商品名稱,商品描述。這些內(nèi)容用戶會(huì)通過(guò)輸入關(guān)鍵詞進(jìn)行查詢,由于內(nèi)容多樣,需要進(jìn)行分詞處理建立索引。
否:不做分詞處理。如:訂單編號(hào)、身份證號(hào),是一個(gè)整體,分詞以后就失去了意義,故不需要分詞。
是否索引(indexed):
是:將Field內(nèi)容進(jìn)行分詞處理后得到的詞(或整體Field內(nèi)容)建立索引,存儲(chǔ)到索引域。索引的目的是為了搜索。如:商品名稱,商品描述需要分詞建立索引。訂單編號(hào),身份證號(hào)作為整體建立索引。只要可能作為用戶查詢條件的詞,都需要索引。
否:不索引。如:商品圖片路徑, 不會(huì)作為查詢條件,不需要建立索引。
是否存儲(chǔ)(stored):
是:將Field值保存到Document中。如:商品名稱,商品價(jià)格。凡是將來(lái)在搜索結(jié)果頁(yè)面展現(xiàn)給用戶的內(nèi)容,都需要存儲(chǔ)。
否:不存儲(chǔ)。如:商品描述內(nèi)容多格式大,不需要直接在搜索結(jié)果頁(yè)面展現(xiàn),所以不做存儲(chǔ)。需要的時(shí)候可以從關(guān)系數(shù)據(jù)庫(kù)獲取。
2.4 Field類型
常用的Field類型見(jiàn)下表:

四. 查詢索引
在test下的com.yx.lucene包下的LuceneTests測(cè)試類中添加查詢索引數(shù)據(jù)的queryIndex()方法。
@Test public void queryIndex() throws IOException { ? ?// 1.指定索引文件存儲(chǔ)的位置 ? ?Directory directory = FSDirectory.open(new File("/Users/yuanxin/Documents/lucene/index")); ? ? // 2.創(chuàng)建一個(gè)用來(lái)讀取索引的對(duì)象IndexReader ? ?IndexReader indexReader = DirectoryReader.open(directory); ? ? // 3.創(chuàng)建一個(gè)用來(lái)查詢索引的對(duì)象IndexSearcher ? ?IndexSearcher indexSearcher = new IndexSearcher(indexReader); ? ? // 使用term查詢:指定查詢的域名和關(guān)鍵字 ? ?// 使用"北京"關(guān)鍵詞搜索沒(méi)有符合的結(jié)果 ? ?// Query query = new TermQuery(new Term("companyName", "北京")); ? ?Query query = new TermQuery(new Term("companyName", "北")); ? ? // 第二個(gè)參數(shù):最多顯示多少條數(shù)據(jù) ? ?TopDocs topDocs = indexSearcher.search(query, 100); ? ?int totalHits = topDocs.totalHits; ? ? // 查詢的總數(shù)量 ? ?System.out.println("符合條件的總數(shù):" + totalHits); ? ?ScoreDoc[] scoreDocs = topDocs.scoreDocs; ? ? // 獲取命中的文檔,存儲(chǔ)的是文檔的id ? ?for (ScoreDoc scoreDoc : scoreDocs) { ? ? ? ?int docID = scoreDoc.doc; // 根據(jù)id查詢文檔 ? ? ? ?Document document = indexSearcher.doc(docID); ? ? ? ? ? ? ? ?System.out.println( "id: " + document.get("id")); ? ? ? ?System.out.println( "companyName: " + document.get("companyName")); ? ? ? ?System.out.println( "companyAddr: " + document.get("companyAddr")); ? ? ? ?System.out.println( "jobName: " + document.get("jobName")); ? ? ? ?System.out.println("----------------------------------------------"); ? ?} }
查看結(jié)果你會(huì)發(fā)現(xiàn),居然沒(méi)有數(shù)據(jù),如果把查詢的關(guān)鍵字“北京”那里改為“北”或“京”就可以,原因是因?yàn)橹形臅?huì)一個(gè)字一個(gè)字的分詞,顯然是不合適的,所以我們需要使用可以合理分詞的分詞器,其中最有名的是IKAnalyzer分詞器。
五. 中文分詞器的使用
1.在pom.xml配置文件中導(dǎo)入IK中文分詞器的依賴。
<!-- IK中文分詞器 --> <dependency> ?<groupId>com.janeluo</groupId> ?<artifactId>ikanalyzer</artifactId> ?<version>2012_u6</version> </dependency>
2.開(kāi)發(fā)者可以配置自己的擴(kuò)展字典(在IKAnalyzer.cfg.xml文件中進(jìn)行配置),將以下文件放到項(xiàng)目的resources目錄下。此步驟不用進(jìn)行配置(使用默認(rèn)即可)。
IKAnalyzer.cfg.xml stopword.dic
3.在createIndex()方法中將創(chuàng)建索引改為使用IKanalyzer類來(lái)完成。
@Test public void createIndex() throws IOException { ? ?// ... ? ?// Analyzer analyzer = new StandardAnalyzer(); // 標(biāo)準(zhǔn)分詞器 ? ?Analyzer analyzer = new IKAnalyzer(); // ... }
4.把原來(lái)的索引文件數(shù)據(jù)刪除(刪除/Users/yuanxin/Documents/lucene/index目錄),再重新運(yùn)行createIndex()方法生成索引文件。
5.在queryIndex()方法中使用關(guān)鍵字“北京”來(lái)查詢數(shù)據(jù)并進(jìn)行測(cè)試。
Query query = new TermQuery(new Term("companyName", "北京")); // Query query = new TermQuery(new Term("companyName", "北"));
考慮一個(gè)問(wèn)題:一個(gè)大型網(wǎng)站中的索引數(shù)據(jù)會(huì)很龐大的,所以使用Lucene這種原生的寫(xiě)代碼的方式就不合適了,因此需要借助一個(gè)成熟的項(xiàng)目或軟件來(lái)實(shí)現(xiàn),目前比較有名是Solr和Elasticsearch。接下來(lái)我們主要學(xué)習(xí)Elasticsearch的使用。
六. 結(jié)語(yǔ)
通過(guò)本小結(jié)的學(xué)習(xí),我們掌握了通過(guò)Lucene編程實(shí)現(xiàn)創(chuàng)建索引、查詢索引等的實(shí)戰(zhàn)操作。同時(shí),進(jìn)一步了解了index、Segment和Field的相關(guān)概念。最后,對(duì)中文分詞器進(jìn)行了介紹。