全文检索的概念

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. Linux 下 简单客户端服务器通讯模型(TCP)

    原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include ...

  2. ZooKeeper 主要的操作演示样品

    // 创建一个与server的连接 ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT, ClientBase.CONN ...

  3. MVC页面声命周期

    MVC页面声命周期 ASP.Net请求处理机制初步探索之旅 - Part 4 WebForm页面生命周期   开篇:上一篇我们了解了所谓的请求处理管道,在众多的事件中微软开放了19个重要的事件给我们, ...

  4. 个人学习JQ插件编写成果:little酷炫的图片滑动切换效果

    工作一个多月了,好久没来冒冒泡了,看了@wayong的JQ插件教程,自己编写了一个模仿拉勾网首页广告栏滑动特效的JQ插件,现在跟朋友们分享分享! 先上demo链接:http://runjs.cn/de ...

  5. intellij idea 13&14 插件推荐及快速上手建议 (已更新!)

    原文:intellij idea 13&14 插件推荐及快速上手建议 (已更新!) 早些年 在外企的时候,公司用的是intellij idea ,当时也是从eclipse.MyEclipse转 ...

  6. 在项目管理工具Redmine中使用SubVersion进行版本管理

    原文:在项目管理工具Redmine中使用SubVersion进行版本管理 在项目管理工具Redmine中使用SubVersion进行版本管理 分类: Redmine2009-06-01 10:11 5 ...

  7. 如何通过js获取iframe框架中的内容

    在父窗口中获取iframe中的元素 IE下:格式:window.frames["iframe的name值"].document.getElementById("ifram ...

  8. [代码收藏]设为首页和加入收藏的JavaScript代码(兼容多浏览器)

    其实不少非IE内核浏览器都仍不支持通过代码将网页设为主页和加入收藏的功能,因此说是兼容,其实只是一个try,catch后的提醒而已. 加入收藏: /* * author : 2010-12-27 11 ...

  9. mysql 安装后无法登陆mysql的 shell 那mysql&gt;经验:ERROR 1045 (28000): Access denied for user &#39;root&#39;@&#39;localhost‘

    [root@hzswtb2-mpc ~]# mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using pas ...

  10. 【jar包】图片的异步加载--【 Imageloader】

    Android Imageloader图片异步加载 Imageloader是一个在android平台下简单的下载.显示.缓存空间的图片加载库. 异步下载网络图片并可以在UI线程更新View,使用二级缓 ...