全文检索的概念

1.从大量的信息中快速、准确的查找要的信息
2.收索的内容是文本信息
3.不是根据语句的意思进行处理的(不处理语义)
4.全面、快速、准确是衡量全文检索系统的关键指标。
5.搜索时英文不区分大小写,结果列表有相关度排序。

全文检索与数据库搜索的区别

1.数据库搜索
Eg: select * from article where content like ‘%here%’
结果where  here
缺点:
1).搜索效果比较差
2).在搜索的结果中,有大量的数据被搜索出来,有很多数据是没有用的
3).查询速度在大量数据的情况下是很难做到快速的
2.全文检索
1).搜索结果按相关度排序,这意味着只有前几个页面对用户来说是比较有用的,其他的结果与用户想要的答案可能相差甚远。数据库搜索时做不到相关度排序的。
2).因为全文检索是采用索引的方式,所以在速度上肯定比数据库方式like要快。
3).所以数据库不能代替全文检索。

Lucene

Lucene:全文检索只是一个概念,而具体实现有很多框架,lucene是其中的一种。

Lucene结构图

说明:
1.索引库中的索引数据是在磁盘上存在的,我们用Directory这个类来描述。
2.我们可以通过API来实现对索引库的增、删、改、查的操作
3.在索引库中各种数据形式可以抽象出一种数据格式Document
4.Document的结构为:Document(List<Field>)
5.Field里存放一个键值对。键值对都为字符串的形式。
6.对索引库中索引的操作实际上也是对Document的操作。

Lucene入门案例

1.搭建工程环境,并导入所需的jar包,至少需要以下四个jar包
lucene-core-3.1.0.jar(核心包)
lucene-analyzers-3.1.0.jar(分词器)
lucene-highlighter-3.1.0.jar(高亮器)
lucene-memory-3.1.0.jar(高亮器)
2.建立索引
步骤:
1)创建IndexWriter对象
2)把JavaBean转化为Document
3)利用IndexWriter.addDocument方法增加索引
4)关闭资源
Eg:

package cn.lsl.lucene.demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test; /*
* 功能1:把一个文章放入索引库中
* */
public class LuceneDemo { @Test
public void testCreatIndex() throws IOException{
//1.获取文章内容
Article article = new Article();
article.setId(1);
article.setTitle("lucene");
article.setContent("提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。");
//把文章放入到索引库中
Directory directory = FSDirectory.open(new File("./indexDir")); //Directory 索引库
//分词器
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
//构造indexWriter对象
IndexWriter indexWriter = new IndexWriter(directory,analyzer,MaxFieldLength.LIMITED);
//把Article转化为Document
Document doc = new Document();
Field idField = new Field("id",article.getId().toString(), Store.YES, Index.NOT_ANALYZED);
Field titleField = new Field("title",article.getTitle(),Store.YES,Index.ANALYZED);
Field contentField = new Field("content",article.getContent(), Store.YES, Index.ANALYZED);
doc.add(idField);
doc.add(titleField);
doc.add(contentField);
indexWriter.addDocument(doc);
indexWriter.close();
}
}

原理图

注:Store这个参数表明是否将内容存放到索引内容中

Index这个参数表明是否存放关键字到索引目录中。

3.进行搜索
步骤:
1)创建IndexSeacher对象
2)创建Query对象
3)进行搜索
4)获得总结果数和前N行记录ID列表
5)根据目录ID把列表Document转化为JavaBean并放入集合中
6)循环出要检索的内容
Eg:

package cn.lsl.lucene.demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test; /*
* 功能:从索引库中把文章检索出来
* */
public class LuceneDemo { //从索引库中吧文章检索出来 @Test
public void testSearch() throws IOException, ParseException{
//1.创建IndexSearch对象
Directory directory = FSDirectory.open(new File("./indexDir"));
IndexSearcher indexSearcher = new IndexSearcher(directory);
//2.创建Query对象
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30, new String[]{"title","content"},analyzer);
//参数为要检索的关键字
Query query = queryParser.parse("lucene");
//3.进行搜索
//query 搜索的条件, 显示N行记录,TopDocs 目录的结果
TopDocs topDocs = indexSearcher.search(query, 10);
//4.获取总记录数和前N行的目录ID列表
ScoreDoc[] scoreDocs = topDocs.scoreDocs; int count = topDocs.totalHits; //总记录数
System.out.println("总记录数:" + count); //5.根据目录的行ID获取每行的document,并吧Article放入集合中
List<Article> articleList = new ArrayList<Article>();
for (int i = 0; i < scoreDocs.length; i++) {
int index = scoreDocs[i].doc; //索引位置,即目录列表ID
float score = scoreDocs[i].score; //相关度得分
System.out.println("得分:"+ score);
Document document = indexSearcher.doc(index);
//把Document转化为Article
Article article = new Article();
article.setId(Integer.valueOf(document.get("id").toString()));
article.setTitle(document.get("title"));
article.setContent(document.get("content"));
articleList.add(article);
} for (Article article : articleList) {
System.out.println("id:" + article.getId());
System.out.println("title:" + article.getTitle());
System.out.println("content:" + article.getContent());
}
}
}

原理图:

保持数据库与索引库同步

在一个系统中,如果索引功能存在,那么数据库和索引库应该是同时存在的。这个时候需要保证索引库的数据和数据库中的数据保持一致性。可以在对数据库进行增删改查操作的同时对索引库也进行相应的操作。这样就可以保持数据库与索引库的一致性。

Lucene的增删改查及API详解

创建工具类:

LuceneConfig.java

package cn.lsl.lucene.util;

import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version; public class LuceneConfig {
public static Analyzer analyzer;
public static Directory directory;
static{
try {
analyzer = new StandardAnalyzer(Version.LUCENE_30);
directory = FSDirectory.open(new File("./indexDir"));
} catch (IOException e) {
e.printStackTrace();
}
}
}

注意:LuceneConfig这个类对Directory和Analyzer进行了包装。

因为在创建IndexWriter时,需要用到这两个类,而管理索引库的操作也都要用到IndexWriter这个类,所以我们对Directory和Analyzer进行了包装

LuceneUtils.java

package cn.lsl.lucene.util;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength; public class LuceneUtils {
public static IndexWriter indexWriter; private LuceneUtils(){} public static IndexWriter getIndexWriter() throws Exception {
if(indexWriter == null){
indexWriter = new IndexWriter(LuceneConfig.directory,LuceneConfig.analyzer,MaxFieldLength.LIMITED);
}
return indexWriter;
}
}

LuceneUtils类对创建IndexWriter进行了封装

因为在一个索引库中只能存在一个IndexWriter对象。(同一个索引库只能有一个IndexWriter进行操作)

所以我们这里采用了单例的模式进行了封装。

DocumentUtils.java

(把JavaBean封装成Document和把Document封装成JavaBean的过程。)

package cn.lsl.lucene.util;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.util.NumericUtils;
import cn.lsl.lucene.demo.Article; public class DocumentUtils {
public static Document article2Document(Article article){
Document document = new Document();
Field idField = new Field("id",article.getId().toString(), Store.YES, Index.NOT_ANALYZED);
Field titleField = new Field("title",article.getTitle(), Store.YES, Index.ANALYZED);
Field contentField = new Field("content",article.getContent(), Store.YES, Index.ANALYZED);
document.add(idField);
document.add(titleField);
document.add(contentField);
return document;
} public static Article document2Article(Document document){
Article article = new Article();
article.setId(Integer.valueOf(document.get("id")));
article.setTitle(document.get("title"));
article.setContent(document.get("content"));
return article;
}
}

什么情况下使用Index.NOT_ANALYZED

当这个属性的值代表的是一个不可分割的整体,例如ID

什么情况下使用Index.ANALYZED

当这个属性的值代表是一个可分割的整体

LuceneManager.java(增删改查例子)

package cn.lsl.lucene.manager;

import java.util.ArrayList;
import java.util.List; import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.Version;
import org.junit.Test; import cn.lsl.lucene.demo.Article;
import cn.lsl.lucene.util.DocumentUtils;
import cn.lsl.lucene.util.LuceneConfig;
import cn.lsl.lucene.util.LuceneUtils; public class LuceneManager { @Test
public void testCreateIndex() throws Exception{
IndexWriter indexWriter = LuceneUtils.getIndexWriter();
Article article = new Article();
article.setId(1);
article.setTitle("lucene");
article.setContent("全文检索");
Document doc = DocumentUtils.article2Document(article);
indexWriter.addDocument(doc);
indexWriter.close();
} @Test
public void testUpdateIndex() throws Exception{
IndexWriter indexWriter = LuceneUtils.getIndexWriter();
Term term = new Term("id","1");
Article article = new Article();
article.setId(1);
article.setTitle("baidu");
article.setContent("百度一下,你就知道");
/*term 关键字 用来进行删除的
* document 是用来进行增加的
* */
indexWriter.updateDocument(term, DocumentUtils.article2Document(article));
indexWriter.close();
} @Test
public void testDeleteIndex() throws Exception{
IndexWriter indexWriter = LuceneUtils.getIndexWriter();
//term 关键字
Term term = new Term("id","1");
indexWriter.deleteDocuments(term);
indexWriter.close();
} @Test
public void testQueryIndex() throws Exception{
IndexSearcher indexSearcher = new IndexSearcher(LuceneConfig.directory); List<Article> articleList = new ArrayList<Article>();
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30, new String[]{"title","content"}, LuceneConfig.analyzer);
Query query = queryParser.parse("lucene");
TopDocs topDocs = indexSearcher.search(query, 10); //索引库
ScoreDoc[] scoreDocs = topDocs.scoreDocs;//索引库数组
int count = topDocs.totalHits; //总记录数
for (int i = 0; i < scoreDocs.length; i++) {
int index = scoreDocs[i].doc; //得到相关的索引
float score = scoreDocs[i].score; //相关度得分
Document document = indexSearcher.doc(index);
Article article = DocumentUtils.document2Article(document);
articleList.add(article);
} for (Article article : articleList) {
System.out.println(article.getId());
System.out.println(article.getTitle());
System.out.println(article.getContent());
}
}
}

Lucene全文检索(一)的更多相关文章

  1. Apache Lucene(全文检索引擎)—创建索引

    目录 返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html 本项目Demo已上传GitHub,欢迎大家fork下载学习:https://gith ...

  2. Lucene全文检索技术

    Lucene全文检索技术 今日大纲 ●    搜索的概念.搜索引擎原理.倒排索引 ●    全文索引的概念 ●    使用Lucene对索引进行CRUD操作 ●    Lucene常用API详解 ●  ...

  3. 使用Lucene全文检索并使用中文版和高亮显示

    使用Lucene全文检索并使用中文版和高亮显示 中文分词需要引入 中文分词发的jar 包,咱们从maven中获取 <!-- lucene中文分词器 --> <dependency&g ...

  4. lucene全文检索基础

    全文检索是一种将文件中所有文本与检索项匹配的文字资料检索方法.比如用户在n个小说文档中检索某个关键词,那么所有包含该关键词的文档都返回给用户.那么应该从哪里入手去实现一个全文检索系统?相信大家都听说过 ...

  5. lucene 全文检索工具的介绍

    Lucene:全文检索工具:这是一种思想,使用的是C语言写出来的 1.Lucene就是apache下的一个全文检索工具,一堆的jar包,我们可以使用lucene做一个谷歌和百度一样的搜索引擎系统 2. ...

  6. Lucene 全文检索 Lucene的使用

    Lucene  全文检索  Lucene的使用 一.简介: 参考百度百科: http://baike.baidu.com/link?url=eBcEVuUL3TbUivRvtgRnMr1s44nTE7 ...

  7. Lucene全文检索_分词_复杂搜索_中文分词器

    1 Lucene简介 Lucene是apache下的一个开源的全文检索引擎工具包. 1.1 全文检索(Full-text Search)  1.1.1 定义 全文检索就是先分词创建索引,再执行搜索的过 ...

  8. Lucene 全文检索

    基于 lucene 8 1 Lucene简介 Lucene是apache下的一个开源的全文检索引擎工具包. 1.1 全文检索(Full-text Search) 全文检索就是先分词创建索引,再执行搜索 ...

  9. Apache Lucene(全文检索引擎)—分词器

    目录 返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html 本项目Demo已上传GitHub,欢迎大家fork下载学习:https://gith ...

  10. lucene全文检索---打酱油的日子

    检索内容,一般的程序员第一时间想到的是sql的like来做模糊查询,其实这样的搜索是比较耗时的.已经有lucene帮我们 封装好了,lucene采用的是分词检索等策略. 1.lucene中的类描述 I ...

随机推荐

  1. exit() _exit()

    图 C程序的启动与终止 差别: _exit()函数:直接使进程停止执行,清除其使用的内存空间,并销毁其在内核中的各种数据结构; exit()函 数则在这些基础上作了一些包装,在运行退出之前加了若干道工 ...

  2. AngularJS之使用服务封装

    AngularJS之使用服务封装可复用代码   创建服务组件 在AngularJS中创建一个服务组件很简单,只需要定义一个具有$get方法的构造函数, 然后使用模块的provider方法进行登记: / ...

  3. MVC 验证码

    验证码类 public class VerifyCode { public string checkCode = String.Empty; public byte[] BuildImg() { in ...

  4. Codeforces 113A-Grammar Lessons(实现)

    A. Grammar Lessons time limit per test 5 seconds memory limit per test 256 megabytes input standard ...

  5. Linux 安装 httpd2.4.16

    假设: apr安装在: /opt/httpd/apr apr-util安装在 /opt/httpd/apr-suite/apr-util apr-iconv安装在/opt/httpd/apr-suit ...

  6. Linux页快速缓存与回写机制分析

    參考 <Linux内核设计与实现> ******************************************* 页快速缓存是linux内核实现的一种主要磁盘缓存,它主要用来降低 ...

  7. node.js + mongodb

    node.js + mongodb 这次内容是结合bootstrap把登陆注册做好,还有就是express的中间件等问题. 看这篇博客之前建议先看我上篇写的那篇博客http://www.cnblogs ...

  8. A在SP.NET跨页多选

    在ASP.NET跨页多选 本文介绍怎样在ASP.NET中实现多页面选择的问题.其详细思路非常easy:用隐藏的INPUT记住每次选择的项目,在进行数据绑定时.检查保存的值,再在DataGrid中进行选 ...

  9. EventBus(事件总线)

    EventBus(事件总线) Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们 ...

  10. Java 多线程之内存一致性错误

    当不同的线程针对相同的数据却读到了不同的值时就发生了内存一致性错误.内存一致性错误的原因是非常复杂的.幸运的是我们程序员不需要详细的理解这些原因,我们需要做的事情就是使用策略来规避这些. 避免内存一致 ...