Lucene API详解

本文详细介绍了Lucene API,包括索引目录、Document与Field、分词器等知识。阐述了索引的添删改操作,以及多种搜索查询方式。还通过项目实战,展示了如何利用Lucene提高文本搜索速度,包括创建索引和搜索索引的步骤,以及集成日志的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lucene API详解
1.索引目录Directory

Directory是一个对索引目录的一个抽象。索引目录用于存放lucene索引文件。直接根据一个文件夹地址来创建索引目录使用SimpleFSDirectory。
MMapDirectory : 针对64系统,它在维护索引库时,会结合“内存”与硬盘同步来处理索引。 SimpleFSDirectory
: 传统的文件系统索引库。 RAMDirectory : 内存索引库

直接使用FsDirectory –系统自动会到后台找对用Directtory处理
源码分析: 通过open方法
在这里插入图片描述

Document可以看出数据库的一条记录

对Document提供的方法主要包括:
indexWriter.deleteAll(); 删除
indexWriter.deleteDocuments(Term ...term);查询出来 在删除
indexWriter.deleteDocuments(Query ... query); 查询出来 在删除
indexWriter.updateDocuments(Term term,....); 更新

Document(行)及IndexableField(列)

当往索引中加入内容的时候,每一条信息用一个Document来表示,Document的意思表示文档,也可以理解成记录,与关系数据表中的一行数据记录类似;
IndexableField表示字段,与关系数据表中的列类似(列数量不定!!),每个Document也由一系列的IndexableField组成,可以理解为数据库的动态列;
在这里插入图片描述

document1.add(IndexableField indexableField); 这里的IndexableField 涉及各种类型:
IndexableField及Field
Field代表Document中的一列数据,相当于一条表记录中的一列。
Lucene提供了一个接口IndexableField,其它的API大多针对这个接口编程,因此Lucene中的列对象实际上是由IndexableField来定义。在实际开发中,主要使用的是Field类的子类。
IndexableField下面的
在这里插入图片描述

其他Field也是属于IndexableField下面的:
我们在构造Field的时候,使用构造方法有三个参数:
在这里插入图片描述

其中有个FieldType类型 在构造FieldType类型的时候,有三个设置的属性

Field的Store方式及Index方式

Lucene中,在创建Field的时候,可以指定Field的store及index属性;
store属性:表示字段值是否存储,Store.YES表示要存储,而Store.NO则表示不存储;
Tokenized表示根据设定的词法分析器来建立该字段的索引;FALSE,不分词;true要分词。
index属性:表示字段的索引方式,
在这里插入图片描述

对于FieldType 选项 下面了解
在这里插入图片描述

对于IndexField 是否存储 理解:
在这里插入图片描述

索引库中实际分为两个部分,一个部分占的空间相对大一些叫做数据区,有Store属性维护,代表是否把字段的内容存到数据区;另一个部分相对小一些,叫做目录区,由Index维护,代表是否支持搜索。
这两则的组合情况:
Store和Index组合使用的适用情况见下图:
在这里插入图片描述

分词Analyzer(词法分析器)
分词器是Lucene中非常重要的一个知识点,如果你面试时说你用过Lucene面试官一定会问你用的什么分词器。
你 今年 挣 了 多少 money?

分词,也称词法分析器(或者叫语言分析器),就是指索引中的内容按什么样的方式来建立,这在全文检索中非常关键,是按英文单词建立索引,还是按中文词意建立索引;这些需要由Analyzer来指定。

建立索引分词,搜索索引添加分词
对于中文,需要采用字典分词,也叫词库分词;把中文件的词全部放置到一个词库中,按某种算法来维护词库内容;如果匹配到就切分出来成为词语。通常词库分词被认为是最理想的中文分词算法。如:“我们是中国人”,效果为:“我们”、“中国人”。(可以使用SmartChineseAnalyzer,“极易分词” MMAnalyzer ,或者是“庖丁分词”分词器、IKAnalyzer。推荐使用IKAnalyzer )
在这里我们推荐IKAnalyzer。使用时需导入IKAnalyzer.jar,并且拷贝IKAnalyzer.cfg.xml,ext_stopword.dic文件,分词器测试代码如下:

(1)使用smartchinese分词器

<dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-smartcn</artifactId>
            <version>5.5.0</version>
        </dependency>

(2) 使用IK分词器

打包本地jar 到maven仓库: 查看扩展知识 mvn install:install-file
-Dfile=IKAnalyzer2012_V5.jar -DgroupId=cn.itsource -DartifactId=ik-analyzer -Dversion=2012_V5 -Dpackaging=jar

publicclass AnalyzerTest {

//创建索引的数据 现在写死,以后根据实际应用场景
private String en = "oh my lady gaga"; // oh my god
private String cn = "迅雷不及掩耳盗铃儿响叮当仁不让";
private String str = "源代码教育FullText Search Lucene框架的学习";


/**
 * 把特定字符串按特定的分词器来分词
 * @param analyzer
 * @param str
 * @throws Exception
 */
public void testAnalyzer(Analyzer analyzer,String str) throws Exception {
	TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(str));

	// 在读取词元流后,需要先重置/重加载一次
	tokenStream.reset();
	while(tokenStream.incrementToken()){
		System.out.println(tokenStream);
	}
}



//词典分词:从词典中查找:需要导入jar包:lucene-analyzers-smartcn-5.5.0.jar,英文支持不太好
@Test
publicvoid testSmartChineseAnalyzer() throws Exception {
	testAnalyzer(new SmartChineseAnalyzer(), str);
}

//IK分词:从词典中查找
// 简单使用:拷贝两个配置文件,拷贝一个jar包
//       扩展词,停止词
//  注意:打开方式,不要使用其他的,直接使用eclipse的text Editor,修改以后要刷新一下让项目重新编译

@Test
publicvoid testIKAnalyzer() throws Exception {
	//true 最大匹配原则
	testAnalyzer(new IKAnalyzer(true), str);
}

}

索引的添删改

经过之前的分析,我们知道对索引的操作统一使用IndexWriter。测试代码如下

    * Document的CRUD
     *    一个document和数据库表中一条记录对应,数据库做crud时,对应document也要唑crud
     * IndexWriter的方法
     *  添加: addDocument
     *  删除:deleteAll deleteDocument(term,query)
     *  修改: updateDocument(term,new Doc) 先删除后添加
    indexWriter.deleteDocuments(new TermQuery(new Term("content","java")));
    indexWriter.forceMergeDeletes();

    indexWriter.addDocument(document);
    ----------------------------------------------------------------------------------
    indexWriter.deleteDocuments(new Term("address","四川"));
    indexWriter.forceMergeDeletes();
    indexWriter.addDocument(doc);
  • IndexSearcher
    查询: doc(docId)
Query及Searcher

搜索是全文检索中最重要的一部分,前面HelloWorld中也发现,Query对象只是一个接口,他有很多子类的实现。在前面直接使用QueryParser的Parse方法来创建Query对象的实例,实际他会根据我们传入的搜索关键字自动解析成需要的查询类型,索引在这里我们也可以直接new一个Query实例来达到不同的搜索效

抽取结构:
// 先做一个准备工作,提供两个search方法 
//一个传入搜索关键字进行搜索
public void search(String key) throws Exception{
		Directory dir=new SimpleFSDirectory(new File(path));
		//创建索引查询器
		IndexSearcher searcher=new IndexSearcher(dir,true);
		//创建查询解析器
		QueryParser qp=new QueryParser(Version.LUCENE_29, "content", new SmartChineseAnalyzer(Version.LUCENE_29));
		//创建查询对象
		Query q=qp.parse(key); 
		System.out.println(“自动生成的查询对象为:”+q.getClass().getSimpleName());
		//执行查询
		TopDocs td=searcher.search(q, 10);
		//遍历结果
		for(int i=0;i<td.scoreDocs.length;i++){
			//得到符合条件的内部文档对象
			ScoreDoc doc=td.scoreDocs[i];
			//得到文档对象
			Document d=searcher.doc(doc.doc);
			System.out.println("score:"+doc.score+"   title:   "+d.get("title")+"     content:"+d.get("content"));
		}
	}

//传入一个查询对象
public void search(Query q) throws Exception{
			System.out.println(“对应的查询语句为:”+q);
		Directory dir=new SimpleFSDirectory(new File(path));
		//创建索引查询器
		IndexSearcher searcher=new IndexSearcher(dir,true);
		//执行查询
		TopDocs td=searcher.search(q, 10);
		//遍历结果
		for(int i=0;i<td.scoreDocs.length;i++){
			//得到符合条件的内部文档对象
			ScoreDoc doc=td.scoreDocs[i];
			//得到文档对象
			Document d=searcher.doc(doc.doc);
			System.out.println("title:   "+d.get("title")+"     content:"+d.get("content"));
		}
	}

1)单词查询

2)段落搜索,要想把多个单词当成一个整体进行搜索,使用双引号包裹

3)通配符搜索

4)模糊搜索

5)临近查询,在段落查询的基础上用“~”后面跟一个1到正无穷的正整数。代表段落中,单词与单词之间最大的间隔数例如: “\”hello
world\”~2” 可以匹配 hello temp1 temp2 world

6)组合查询

项目实战

关系型数据库对于前面有变化的文本搜索(like
%keyword%),索引会失效。查询速度非常低。可以使用lucene提高速度,比如我们的系统日志/登录日志,一个系统中有很多的日志信息的,用户在进行检索的时候很麻烦,我们可以使用lucene进行全文检索。(画图演示)

项目架构

.创建索引
创建索引方式
1)即时同步

添加数据库的同时添加到索引库,效率变低。对于实时性不高的数据,同步需要花时间,需放到空闲时间操作。
2)实时同步

在特定的时间,把没有同步的数据同步一次。
3)手动同步

手动同步可以很快转换到定时同步,只需加一个定时调度就ok,我们采用的是手动同步。
实现步骤

1、前台,在页面中添加一个“重建索引”按钮。
2、前台,点击“重建索引”后,调用后台controller方法。
3、后台,查询需要创建索引的对象列表
4、后台,遍历这些对象,封装成Document对象 5、后台,添加索引

搜索索引

步骤:

1、前台,提供一个“搜索”按钮,点击后定位到搜索页面
2、前台,提供一个新的“搜索”页面,搜索页面里面一个查询表单,查询表单下面放查询内容 注意:前台传递到后台需要串基本数据类的名称.
3、后台,接收查询条件,封装到查询对象
4、后台,把“查询对象”传入Service完成查询
a)使用“查询对象”产出Lucene的Query对象 b)使用Query完成Lucene索引库的查询
5、后台,把结果封装,返回。

6.4.2. Luence集成日志
代码生成页面 service mapper controller
导入Luence工具类

在service层 写两个方法
updateIndex
覆写分页的方法完成

代码说明: (1)Service层定义方法 ,加入索引库

@Override
public void updateIndex() {
    //查收所有数据到日志库
    List<Systemlog> systemlogList = systemlogMapper.selectAll();
    //写索引库
    for (Systemlog systemlog : systemlogList) {
        Document document = new Document();
        document.add(new TextField("id",String.valueOf(systemlog.getId()), Field.Store.YES));
        document.add(new TextField("function",String.valueOf(systemlog.getFunction()), Field.Store.YES));
        document.add(new TextField("opip",String.valueOf(systemlog.getOpip()), Field.Store.YES));
        document.add(new TextField("optime",String.valueOf(systemlog.getOptime()), Field.Store.YES));
        document.add(new TextField("opuser",String.valueOf(systemlog.getOpuser()), Field.Store.YES));
        document.add(new TextField("params",String.valueOf(systemlog.getParams()), Field.Store.YES));
        LuceneUtil.addIndex(document);
    }
    //关闭资源
    LuceneUtil.closeAll();

}

(2)覆写分页方法:

@Override
public PageList<Systemlog> getByQuery(BaseQuery query) {
    PageList<Systemlog> pageList = new PageList<>();
    //查询字段
    String[] fields = {"function"};
//关键字 比如 function字段里面 Login
    String q = query.getQ(); save
    //设置条数
    pageList.setTotal(LuceneUtil.totalHits(fields,q));

    //命中的document
    List<Document> hitDocuments = LuceneUtil.getHitDocuments(fields, q, query.getPage(), query.getRows());
    List<Systemlog> logList = new ArrayList<>();
    for (Document hitdocument : hitDocuments) {
        //把每一个doucment转换成SystemLog
        Systemlog systemlog1 = new Systemlog();
        systemlog1.setId(Long.valueOf(hitdocument.get("id")));
        systemlog1.setFunction(hitdocument.get("function"));
        systemlog1.setOpip(hitdocument.get("opip"));
        systemlog1.setOptime(hitdocument.get("opttime"));
        systemlog1.setOpuser(hitdocument.get("opuser"));
        systemlog1.setParams(hitdocument.get("params"));
        logList.add(systemlog1);
    }
    pageList.setRows(logList);
    return pageList;
}

工具类 说明: LuceneUtil.getHitDocuments

public static List<Document> getHitDocuments(String[] field,String queryStr,int pageNum,int pageSize){

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

    try {
        IndexSearcher indexSearcher = getIndexSearcher();
        Query query = createQuery(field,queryStr);
        System.out.println(query);

        // 查询数据, 结束页面自前的数据都会查询到,但是只取本页的数据 比如pageNum =1 pageSize=10 ,查询前面10条记录 如pageNum=2 查询 前20条记录  PageNum=3 pageSize=10查询前3条数据


        TopDocs topDocs = indexSearcher.search(query, pageNum * pageSize);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        //总条目数  2   10  
        int totalHits = topDocs.totalHits;

        int start = (pageNum-1)*pageSize;   //10
        int end = (pageNum*pageSize)>totalHits ?totalHits:(pageNum*pageSize);  //20


        for(int i=start;i<end;i++){
            ScoreDoc scoreDoc = scoreDocs[i];
            Document document = indexSearcher.doc(scoreDoc.doc);
            list.add(document);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return list;
}


高亮(根据需要加入)

1. 高亮知识点
   ① 导入jar包 lucene-highlighter-5.5.0.jar
    lucene-memory-5.5.0.jar
     ② 创建高亮器 
     ③ 使用高亮器对查询结果进行高亮处理

Maven依赖本地jar包:导入lib文件夹中:

  使用maven把本地jar包导入maven本地仓库:

1:定位到jar包目录
2:进入cmd命令行:

3:输入命令:

mvn install:install-file -Dfile=D:\itsource\IKAnalyzer2012_V5.jar
-DgroupId=cn.itsource -DartifactId=ik-analyzer -Dversion=2012_V5 -Dpackaging=jar

mvn install:install-file ===》安装命令
-Dfile=D:\itsource\IKAnalyzer2012_V5.jar  =定位到你的jar文件

-DgroupId=cn.itsource -DartifactId=ik-analyzer -Dversion=2012_V5  ==》坐标

-Dpackaging=jar 打包类型


现在就可以像使用spring等一样,在pom文件中引入你的坐标了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值