lucene全文检索精华

更新时间:2024-01-17 02:04:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

lucene全文检索

1 概念

全文检索(Full-Text Retrieval)是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程.

1.1 lucene全文检索的特性

全文检索(Full-Text Retrieval)是指以文本作为检索对象,找出含有指定词汇的文本。全面、准确和快速是衡量全文检索系统的关键指标。

关于全文检索的特性,我们要知道:1,只处理文本。2,不处理语义。3,搜索时英文不区分大小写。4,结果列表有相关度排序。

下图就是显示“1+1等于几”这个搜索要求对应的结果。可以看到,是没有“2”这个结果的,结果页面都是出现了这些词的网页 .

1.2 全文检索的应用场景

我们使用Lucene,主要是做站内搜索,即对一个系统内的资源进行搜索。如BBS、BLOG中的文章搜索,网上商店中的商品搜索等。使用Lucene的项目有Eclipse、Jira等。一般不做互联网中资源的搜索,因为不易获取与管理海量资源(专业搜索方向的公司除外)。

2 第一个lunece程序

2.1 准备lucene的开发环境

搭建Lucene的开发环境只需要加入Lucene的Jar包,要加入的jar包至少要有: ? lucene-core-4.4.0.jar(核心包)

? analysis\\common\\lucene-analyzers-common-4.4.0.jar(分词器) ? highlighter\\lucene-highlighter-4.4.0.jar(高亮) ? \\memory\\lucene-memory-4.4.0.jar(高亮)

? queryparser\\ lucene-queryparser-4.4.0.jar (查询解析)

2.2 实现建立索引功能(IndexWriter)

/**

* 使用indexWriter对数据库建立索引.. * @throws IOException */ @Test

public void createIndex() throws IOException{

//索引存放的位置...

Directory directory=FSDirectory.open(new File(\));

//lucene当前使用的匹配版本

Version matchVersion=Version.LUCENE_44;

//分词器,对文本进行分词,抽象类,由子类实现不同的分词方式

Analyzer analyzer=new StandardAnalyzer(matchVersion); //索引写入的配置

IndexWriterConfig indexWriterConfig=new

//构建用于操作索引的类

IndexWriter indexWriter=new IndexWriter(directory,

IndexWriterConfig(matchVersion, analyzer);

indexWriterConfig);

//索引库里面的要遵守一定的结构,(索引结构...) 在索引库当中保存的都是document

Document doc=new Document(); //索引document里面页游很多的字段... /**

* 1:字段的名称 * 2:字段对应的值

* 3:该字段在索引库中是否存储 */

IndexableField id=new IntField(\, 1, Store.YES);

//StringField不会根据分词器去拆分,只有后面的String全包括才能被搜索到 IndexableField title=new StringField(\, \培训,传智播客//TextField如果按照默认分词器去拆分,中文则是按照单个中文拆分的

专注Java培训10年\, Store.YES);

IndexableField content=new TextField(\, \培训的龙头老

大,口碑最好的java培训机构,进来看看同学们的呐喊\, Store.YES); doc.add(id);

}

doc.add(title); doc.add(content);

indexWriter.addDocument(doc);

indexWriter.close();

2.3 实现搜索功能(IndexSearcher)

/**

* 使用indexSearcher对数据进行搜索 * @throws IOException */ @Test

public void queryIndex() throws IOException{

//索引存放的位置

Directory directory=FSDirectory.open(new File(\)); //创建索引读取器

IndexReader indexReader=DirectoryReader.open(directory);

//通过indexSearcher去检索索引目录...

IndexSearcher indexSearcher=new IndexSearcher(indexReader);

//我们以后只要根据索引查找,整个过程肯定要分2次..

//这是一个搜索条件..,通过定义条件来进行查找...(可以拿到编号,编号都放在了//term 我需要根据哪个字段进行检索,字段对应的值...

//Query是抽象类,由子类去实现不同的查询规则

Query query=new TermQuery(new Term(\, \));

//搜索先搜索索引目录(第一次搜)..不会直接搜索到document(第二次搜) //找到符合query条件的前面N条记录...如果不加条件则会全部查询出来

ScoreDoc数组中,遍历数组就获得了编号)

TopDocs topDocs=indexSearcher.search(query, 10); System.out.println(\总记录数是:\+topDocs.totalHits);

//返回结果的数组(得分文档)

ScoreDoc[] scoreDocs=topDocs.scoreDocs; //返回一个击中..

for(ScoreDoc scoreDoc:scoreDocs){

int docID=scoreDoc.doc; //根据编号去击中对应的文档

//lucene的索引库里有很多document,lucene为每个document定义一个编号,唯一标识(docId),是自增长的。 Document document=indexSearcher.doc(docID); }

System.out.println(document.get(\)); System.out.println(document.get(\)); System.out.println(document.get(\));

}

2.4 创建索引与搜索的原理分析 2.4.1 建立索引的执行过程

在建立索引时,先要把文档存到索引库中,还要更新词汇表。如下图:

1. 我们做的操作:把数据对象转成相应的Document,其中的属性转为Field。 2. 我们做的操作:调用工具IndexWriter的addDocument(doc),把Document添加

到索引库中。

3. Lucene做的操作:把文档存到索引库中,并自动指定一个内部编号,用来唯一标识这

条数据。内部编号类似于这条数据的地址,在索引库内部的数据进行调整后,这个编号就可能会改变,同时词汇表中引用的编号也会做相应改变,以保证正确。但我们如果在外面引用了这个编号,前后两次去取,得到的可能不是同一个文档!所以内部编号最好只在内部用。

4. Lucene做的操作:更新词汇表。把文本中的词找出并放到词汇表中,建立与文档的对

应关系。要把哪些词放到词汇表中呢,也就是文本中包含哪些词呢?这就用到了一个叫做Analyzer(分词器)的工具。他的作用是把一段文本中的词按规则取出所包含的所有词。对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由子类实现的,所以对于不同的语言(规则),要用不同的分词器。如下图:

在把对象的属性转为Field时,相关代码为:doc.add(new Field(\,

article.getTitle(), Store.YES, Index.ANALYZED))。第三与第四个参数的意思为:

枚举类型 Store NO 枚举常量 不存储属性的值 存储属性的值 不建立索引 分词后建立索引 说明 YES Index NO ANALYZED NOT_ANALYZED 不分词,把整个内容作为一个词建立索引 说明:Store是影响搜索出的结果中是否有指定属性的原始内容。Index是影响是否可以从这个属性中查询(No),或是查询时可以查其中的某些词(ANALYZED),还是要把整个内容作为一个词进行查询(NOT_ANALYZED)。

2.4.2 在索引库中搜索的执行过程

在进行搜索时,先在词汇表中查找,得到符合条件的文档编号列表。再根据文档编号真正的去取出数据(Document)。如下图:

1. 把要查询字符串(查询条件)转为Query对象(这就像在Hibernate中使用HQL查询

时,也要先调用Session.createQuery(hql)转成Hibernate的Query对象一样)。把查询字符串转换成Query是使用QueryParser,或使用

MultiFieldQueryParser(查询字符串也要先经过Analyzer(分词器)。要求搜索时使用的Analyzer要与建立索引时使用的Analzyer要一致,否则可能搜不出正确的结果)。

2. 调用IndexSearcher.search(),进行查询,得到结果。此方法返回值为TopDocs,

是包含结果的多个信息的一个对象。其中有totalHits 代表决记录数,ScoreDoc的数组。ScoreDoc是代表一个结果的相关度得分与文档编号等信息的对象。 3. 取出要用到的数据列表。调用IndexSearcher.doc(scoreDoc.doc)以取出指定编号对应的Document数据。在分页时要用到:一次只取一页的数据。

3 lunece索引库操作CRUD

3.1 全文检索程序的工作流程

从上图可以看出,我们不仅要搜索,还要保证数据集合与索引库的一致性。所以对于全文检索功能的开发,要做的有两个方面:索引库管理(维护索引库中的数据)、在索引库中进行搜索。而Lucene就是操作索引库的工具。

3.2 使用lucene的API操作索引库

索引库是一个目录,里面是一些二进制文件,就如同数据库,所有的数据也是以文件的形式存在文件系统中的。我们不能直接操作这些二进制文件,而是使用Lucene提供的API完成相应的操作,就像操作数据库应使用SQL语句一样。

对索引库的操作可以分为两种:管理与查询。管理索引库使用IndexWriter,从索引库中查询使用IndexSearcher。Lucene的数据结构为Document与Field。Document代表一条数据,Field代表数据中的一个属性。一个Document中有多个Field,Field的值为String型,因为Lucene只处理文本。

我们只需要把在我们的程序中的对象转成Document,就可以交给Lucene管理了,搜索的结果中的数据列表也是Document的集合。

3.3 添加(C)操作

3.3.1 先准备pojo对象

public class Article {

private int id;//编号 private String title;//题目 private String author;//作者 private String content;//内容 private String link;//链接

3.3.2 执行添加操作

public void addIndex(Article article) throws IOException{

}

IndexWriter indexWriter=LuceneUtil.getIndexWriter(); Document doc=ArticleUtil.articleToDocument(article); indexWriter.addDocument(doc); indexWriter.close();

从上面可以看出我们需要自己定义一个LuceneUtil工具类,目地就是为了方便的获取IndexWriter和IndexSearcher,还需要一个ArticleUtil工具类,目地是为了方便的把对象转化为document和document转化为对象。

3.3.3 编写LuceneUtil工具类

public class LuceneUtil {

private static Directory directory=null;

private static IndexWriterConfig indexWriterConfig=null; private static Version matchVersion=null; private static Analyzer analyzer=null; static{

try {

//Constants.INDEX_URL是自己定义的常量,public static final

//String INDEX_URL=\

}

//得到indexWriter

public static IndexWriter getIndexWriter() throws IOException{ }

//得到indexSearcher

public static IndexSearcher getIndexSearcher() throws IOException{

IndexReader indexReader=DirectoryReader.open(directory); IndexSearcher indexSearcher=new IndexSearcher(indexReader); return indexSearcher;

IndexWriter indexWriter=new IndexWriter(directory, return indexWriter;

directory=FSDirectory.open(new File(Constants.INDEX_URL)); matchVersion=Version.LUCENE_44;

analyzer=new StandardAnalyzer(matchVersion);

indexWriterConfig=new IndexWriterConfig(matchVersion,

analyzer);

} catch (IOException e) { }

e.printStackTrace();

indexWriterConfig);

}

}

public static Version getMatchVersion() { }

public static Analyzer getAnalyzer() { }

return analyzer; return matchVersion;

3.3.4 编写ArticleUtil工具类

public class ArticleUtil { }

//把对象转化为document

public static Document articleToDocument(Article article){ }

//把document转为对象

public static Article documentToArticle(Document document){ }

Article article=new Article();

article.setId(Integer.parseInt(document.get(\))); article.setAuthor(document.get(\)); article.setTitle(document.get(\)); article.setLink(document.get(\)); article.setContent(document.get(\)); return article;

Document document=new Document();

document.add(new IntField(\, article.getId(), Store.YES)); document.add(new StringField(\, article.getAuthor(), document.add(new StringField(\, article.getLink(), document.add(new TextField(\, article.getTitle(), document.add(new TextField(\, article.getContent(),

return document;

Store.YES)); Store.YES)); Store.YES)); Store.YES));

3.3.5 测试代码

private ArticleDao articleDao=new ArticleDao();

@Test

public void testIndexWriter() throws IOException{

Article article=new Article(1, \青岛\, \小磊\, \青岛八大关秋天

最美,最喜欢枫叶maple\, \); articleDao.addIndex(article);

}

3.4 查询(R)操作 3.4.1 查询代码

//查询 public List queryIndex(String keyword) throws Exception{

IndexSearcher indexSearcher=LuceneUtil.getIndexSearcher(); String[] fields={\,\}; //这里用了新的查询方式

QueryParser queryParser=new

MultiFieldQueryParser(LuceneUtil.getMatchVersion(), fields, LuceneUtil.getAnalyzer());

}

//根据keyword来检索数据

Query query=queryParser.parse(keyword);

TopDocs topDocs=indexSearcher.search(query, 100);

System.out.println(\检索出符合的数据一共有\+topDocs.totalHits); ScoreDoc[] scoreDocs=topDocs.scoreDocs;

List articles=new ArrayList(); for(ScoreDoc scoreDoc:scoreDocs){ }

return articles;

int docID=scoreDoc.doc;

Document document=indexSearcher.doc(docID);

Article article=ArticleUtil.documentToArticle(document); articles.add(article);

3.4.2 测试代码

@Test

public void testQueryIndex() throws Exception{

}

List articles=articleDao.queryIndex(\八大关\); for(Article article:articles){ }

System.out.println(article);

3.4.3 测试结果

3.5 查询+分页操作 3.5.1 分页代码

3.5.2 测试代码

@Test

public void testQueryPageIndex() throws Exception{ }

List articles=articleDao.queryIndex(\八大关\,20,10); for(Article article:articles){ }

System.out.println(article);

3.5.3 测试结果

3.6 删除操作 3.6.1 删除代码

public void delIndex(String fileName,String fileValue) throws IOException{

IndexWriter indexWriter=LuceneUtil.getIndexWriter();

Term term=new Term(fileName, fileValue);//Term方式查找,单个单个词

查找方式 indexWriter.deleteDocuments(term);

}

indexWriter.close();

3.6.2 测试代码

@Test

public void testDel() throws IOException{ articleDao.delIndex(\, \小磊\); }

再次查询发现索引库中所有数据都被删除。

3.7 更新操作 3.7.1 更新代码

public void updateIndex(String fileName,String fileValue,Article article) throws IOException{

IndexWriter indexWriter=LuceneUtil.getIndexWriter();

Term term=new Term(fileName, fileValue);

Document doc=ArticleUtil.articleToDocument(article);

indexWriter.updateDocument(term, doc);

}

indexWriter.close();

3.7.2 测试代码

@Test

public void testUpdate() throws IOException{

Article article=new Article(1587, \大更新\, \临沂\, \大美临沂\, \);

articleDao.updateIndex(\, \大\, article); }

更新的这条刚开始索引库中是没有的,再次查询发现索引库中有了刚刚更新的这条数据。得知

索引文件的检索与维护,更新是先删除后创建,所以更新操作需要较高的代价。因为文档修改后(即使是很小的修改),就可能会造成文档中的很多的关键词的位置都发生了变化,这就需要频繁的读取和修改记录,这种代价是相当高的。因此,一般不进行真正的更新操作,而是使用“先删除,再创建”的方式代替更新操作。

4 分词器

4.1 分词器的作用

在创建索引时会用到分词器,在使用字符串搜索时也会用到分词器,这两个地方要使用同一个分词器,否则可能会搜索不出结果。

Analyzer(分词器)的作用是把一段文本中的词按规则取出所包含的所有词。对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由子类实现的,所以对于不同的语言(规则),要用不同的分词器。如下图:

4.2 分词器的工作流程

分词器的一般工作流程:

1, 切分关键词 2, 去除停用词

3,对于英文单词,把所有字母转为小写(搜索时不区分大小写)

说明:有的分词器还对英文进行形态还原,就是去除单词词尾的形态变化,将其还原为词的原形。这样做可以搜索出更多有意义的结果。如搜索sutdent时,也可以搜索出students,这是很有用的。

4.3 停用词

有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响,例如英文的“a、an、the、of”,或中文的“的、了、着、是”,以及各种标点符号等,这样的词称为停用词(stop word)。文本经过分词之后,停用词通常被过滤掉,不会被进行索引。在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉(因为用户输入的查询字符串也要进行分词处理)。排除停用词可以加快建立索引的速度,减小索引库文件的大小。

4.4 常用的中文分词器

中文的分词比较复杂,因为不是一个字就是一个词,而且一个词在另外一个地方就可能不是一个词,如在“帽子和服装”中,“和服”就不是一个词。对于中文分词,通常有三种方式:单字分词、二分法分词、词典分词。

4.4.1 单字分词

就是按照中文一个字一个字地进行分词。如:“我们是中国人”

效果:“我”、“们”、“是”、“中”、“国”、“人”。(StandardAnalyzer就是这样)。英文按照空格来分。

4.4.2 二分法分词

按两个字进行切分。如:“我们是中国人”,效果:“我们”、“们是”、“是中”、“中国”、“国人”。(CJKAnalyzer就是这样)。英文按照空格来分。

4.4.3 词典分词

按某种算法构造词,然后去匹配已建好的词库集合,如果匹配到就切分出来成为词语。通常

词库分词被认为是最理想的中文分词算法。如:“我们是中国人”,效果为:“我们”、“中国人”。

常见的词典分词有:极易分词:MMAnalyzer和庖丁分词:PaodingAnalzyer

4.4.3.1 庖丁分词的步骤

1、导入IK Analyzer 2012FF_hf1.zip包

2、引入分词器的配置文件IKAnalyzer.cfg.xml(配置停用词和自定义扩展词), 放到类路径下(src下)

3、引入ext_stopword.dic文件(存放停用词),放置到类路径下 如果要新增停用词,只需换一行写便可。刷新下项目。 4、新建ext_dict.dic文件(存放自定义的扩展词),放置到类路径下

4.5 测试分词器的代码

//测试分词器的代码 public static void testAnalyer(Analyzer analyzer, String text)

throws IOException {

System.out.println(\当前使用的分词器:\ + analyzer.getClass().getSimpleName());

}

TokenStream tokenStream = analyzer.tokenStream(\,

new StringReader(text));

tokenStream.addAttribute(CharTermAttribute.class); tokenStream.reset();

while (tokenStream.incrementToken()) { }

CharTermAttribute charTermAttribute = tokenStream

.getAttribute(CharTermAttribute.class);

System.out.println(new

String(charTermAttribute.toString()));

5 lucene全文检索和数据库检索的区别

6 lucene全文检索的得分

1,相关度得分是在查询时根据查询条件实进计算出来的

2,如果索引库数据不变,查询条件不变,查出的文档得分也不变

我们可以人工干预得分。索引库中的数据都是在对象转化为document之后添加进去的,所以我们可以在转化这个步骤进行干预。

其中的boost权限值默认为1f,上图修改成了4f,则新添加的数据就会排在前面

通过改变文档Boost值来改变排序结果。Boost是指索引建立过程中,给整篇文档或者文档的某一特定属性设定的权值因子,在检索时,优先返回分数高的。通过Document对象的setBoost()方法和Field对象的setBoost()方法,可以分别为Document和Field指定Boost参数。不同在于前者对文档中每一个域都修改了参数,而后者只针对指定域进行修改。默认值为1F,一般不做修改。

百度也由此来干预显示结果排序!

排序结果还与点击率,网站代码优化等相关。

7 优化索引库

优化这个问题是比较纠结的,索引优化也是很费资源和时间的,但是优化索引也是提高检索速度的重要方法,因此需要好好权衡这一点。还有就是在lucene3.6后面的版本中lucene可以自动进行索引的优化,当索引的数目达到一定的量之后会自动进行索引的优化 .

注意:如果不手动优化索引,lucene会根据生成的索引文件的段数来判断,进而自己进行索引文件的合并和索引的优化等操作。 建议不要手动优化,因为优化索引是一个很废资源的过程。

7.1 合并索引库

IndexWriterConfig indexWriterConfig = new IndexWriterConfig(

Version.LUCENE_44, new

StandardAnalyzer(Version.LUCENE_44));

// 创建索引库优化对象...

LogMergePolicy logMergePolicy = new LogByteSizeMergePolicy(); // 值越小,搜索的时候越快,创建索引的时候越慢 // 值越大,搜索的时候越慢,创建索引的时候越快。 logMergePolicy.setMergeFactor(3); // 设置segment最大合并文档(Document)数 // 值较小有利于追加索引的速度

// 值较大,适合批量建立索引和更快的搜索

logMergePolicy.setMaxMergeDocs(1000);

indexWriterConfig.setMergePolicy(logMergePolicy);

7.2 使用RAMDirectory

Lucene的API接口设计的比较通用,输入输出结构都很像数据库的表==>记录==>字段,所以很多传统的应用的文件、数据库等都可以比较方便的映射到Lucene的存储结构/接口中。总体上看:可以先把Lucene当成一个支持全文索引的数据库系统。

Lucene的索引存储位置使用的是一个接口(抽象类),也就可以实现各种各样的实际存储方式(实现类、子类),比如存到文件系统中,存在内存中、存在数据库中等等。Lucene提供了两个子类:FSDirectory与RAMDirectory。

1, FSDirectory:在文件系统中,是真实的文件夹与文件。

2, RAMDirectory:在内存中,是模拟的文件夹与文件。与FSDirectory相比:1

因为没有IO操作,所以速度快。2,因为在内存中,所以在程序退出后索引库数据就不存在了。

@Test

public void testRamDirectory() throws Exception {

// 创建索引目录

Directory fsDir = FSDirectory.open(new File(\)); // 通过此对象可将硬盘上的索引读到内存中,涉及io操作... IOContext context = new IOContext();

// 将磁盘中的索引加载到内存当中,以后每次操作索引的时候,直接操作内存中的索

引即可,不用操作硬盘 Directory ramDir = new RAMDirectory(fsDir, context); }

// 构造索引读取器

IndexReader indexReader = DirectoryReader.open(ramDir); IndexSearcher indexSearcher = new IndexSearcher(indexReader); Query query = new TermQuery(new Term(\, \)); TopDocs docs = indexSearcher.search(query, 10); System.out.println(docs.totalHits);

7.3 其他优化方式

1. 排除停用词方式:排除停用,被分词器过滤掉,词就不会建立索引,索引文件就会变小,

这样搜索的时候就会变快。

2. 索引数据分区存放:给索引归类,引入路由功能。 3. 通过查询条件进行优化

8 排序和过滤

这2个都是在搜索索引库的时候进行的。IndexSearcher.search();

8.1 排序

//排序

SortField field=new SortField(\, Type.INT); Sort sort=new Sort(); sort.setSort(field);

TopDocs topDocs=indexSearcher.search(query, 100 ,sort);

默认的是按照升序排序的,如果想按照降序排序则在SortField参数中加true。 SortField field=new SortField(\, Type.INT,true);

8.2 过滤

使用Filter可以对搜索结果进行过滤以获得更小范围的结果。使用Filter对性能的影响很大(有可能会使查询慢上百倍)。但也可使用相应的查询实现一样的效果。

// indexSearcher.search(query, n);

// indexSearcher.search(query, filter, n); // indexSearcher.search(query, filter, n, sort); //过滤

//1,需要哪个字段进行过滤 2,字段对应的最小值 3,字段对应的最大值

//4,是否包含最小值 5,是否包含最大值

Filter filter=NumericRangeFilter.newIntRange(\, 1, 10, true, true);

TopDocs topDocs=indexSearcher.search(query,filter, 100);

9 lucene的各种查询

9.1 关键字查询TermQuery

// 关键词查询 @Test

public void testTermQuery() {

// 对应的查询字符串为:title:lucene

Query query = new TermQuery(new Term(\, \)); }

9.2 使用查询字符串+QueryParser的查询方式

1、QueryParser:只在一个字段中查询

2、MultiFieldQueryParser:可以在多个字段查询

// 字符串查询 @Test

public void testParserQuery() throws ParseException {

String[] fields={\,\}; //字符串搜索

QueryParser queryParser=new

MultiFieldQueryParser(LuceneUtil.getMatchVersion(), fields, LuceneUtil.getAnalyzer());

}

//根据关键字java来检索数据

Query query=queryParser.parse(\);

9.3 查询所有MatchAllDocsQuery

// 查询所有 @Test

public void testMatchAllDocsQuery() { // 对应的查询字符串为:*:*

Query query = new MatchAllDocsQuery(); }

9.4 范围查询NumericRangeQuery

// 范围查询 @Test

public void testNumericRangeQuery() { }

Query query = NumericRangeQuery.newIntRange(\, 1, 10, false,

false);

这种方式和过滤相比,效率要比过滤要高,推荐用这种。

9.5 通配符查询WildcardQuery

// ? 代表1个任意字符 // * 代表0或多个任意字符 @Test

public void testWildcardQuery() {

// 对应的查询字符串为:title:lu*n?

Query query = new WildcardQuery(new Term(\, \)); }

9.6 模糊查询FuzzyQuery

// 模糊查询 @Test

public void testFuzzyQuery() {

// //最大的可编辑数,不用被编辑的数量

FuzzyQuery query=new FuzzyQuery(new Term(\,\习精\)); }

默认是在搜索文本相差2个字符都可以。最后一个参数可以改变(取值范围0,1,2表示允许我的查询条件的值,可以错误几个字符)。

FuzzyQuery query=new FuzzyQuery(new Term(\,\习精\),0);0表示不允许错误,这样必须和搜索文本一样才可以。

9.7 短语查询PhraseQuery

// 短语查询 @Test

public void testPhraseQuery() {

PhraseQuery phraseQuery = new PhraseQuery(); // // 对应的查询字符串为:title:\框架\

// phraseQuery.add(new Term(“title”, “lucene”), 0); // 0表示第 // phraseQuery.add(new Term(\框架\ // 对应的查询字符串为:title:\框架\

1个位置

phraseQuery.add(new Term(\, \)); phraseQuery.add(new Term(\, \框架\));

phraseQuery.setSlop(5); // 之间的间隔最大不超过5个词,范围越大,匹配

的越多,性能也就越慢。

}

public void add(Term term, int position) public void setSlop(int s)

例:add( new Term(“name”, “lucene”, 1); add(new Term(“name”, “教程”, 3);

代表搜索的是“Lucene ? 教程”,?表示中间隔一个词。 setSlop(2);

代表这两个词中间可以最多隔2个词

9.8 布尔查询BooleanQuery

// 布尔查询 @Test

public void testBooleanQuery() {

BooleanQuery booleanQuery = new BooleanQuery(); // booleanQuery.add(query, Occur.MUST); // 必须满足 // booleanQuery.add(query, Occur.MUST_NOT); // 非

// booleanQuery.add(query, Occur.SHOULD); // 多个SHOULD一起用是

OR的关系

// // 对应的查询字符串为:+*:* -id:{5 TO 15] // // 对应的查询字符串为:*:* NOT id:{5 TO 15] // booleanQuery.add(query1, Occur.MUST); // booleanQuery.add(query2, Occur.MUST_NOT); }

Query query1 = new MatchAllDocsQuery();

Query query2 = NumericRangeQuery.newIntRange(\, 5, 15, false,

true);

public void add(Query query, Occur occur)

Occur 用于表示布尔查询子句关系的类,包括:

Occur.MUST,Occur.MUST_NOT,Occur.SHOULD。

1, MUST和MUST:取得连个查询子句的交集。

2, MUST和MUST_NOT:包含MUST并且查询结果中不包含MUST_NOT的检索结果。 3, SHOULD与SHOULD,表示“或”关系,最终检索结果为所有检索子句的并集。

一般不单独使用,因为单独就不应使用BooleanQuery了。

使用时注意:

1, 单独使用MUST_NOT:无意义,检索无结果。(也不报错) 2, 单独使用SHOULD:结果相当于MUST。

3, MUST_NOT和MUST_NOT:无意义,检索无结果。(也不报错)

4, SHOULD和MUST_NOT: 此时SHOULD相当于MUST,结果同MUST和MUST_NOT。 5, MUST和SHOULD:此时SHOULD无意义,结果为MUST子句的检索结果。

10 高亮

对查询出来的关键字进行高亮。

10.1 高亮所需的jar包

highlighter\\lucene-highlighter-4.4.0.jar memory\\lucene-memory-4.4.0.jar

10.2 高亮的特点

1、高亮将文本生成一段摘要,用于搜索,并把摘要中的关键词高亮显示 2、摘要的大小可以配置,默认100个字符。

3、文本实现高亮的效果,就是在需要高亮的文字前后加前缀与后缀(类似Html)

10.3 实现高亮效果的代码

// 创建高亮器,指定html Formatter formatter = new SimpleHTMLFormatter(\

class='kw'>\, \);

// 使用高亮器:对content属性值进行摘要并高亮 String text =

//query里面条件,条件里面有搜索关键字

Scorer scorer = new QueryScorer(query);

//设定高亮显示的格式,也就是对高亮显示的词组加上前缀后缀

Highlighter highlighter = new Highlighter(formatter, scorer); //设置返回摘要的长度...

highlighter.setTextFragmenter(new SimpleFragmenter(20));

highlighter.getBestFragment(LuceneUtil.getAnalyzer(), \, document.get(\));

// 如果进行高亮的属性值中没有要搜索的关键字,则返回null if (text != null) {

document.getField(\).setContent(text); }

11 爬虫

java UrlConnect或者httpClient来实现 rss:信息聚合

每个网站都提供一个链接,都遵守相同的标准,通过这个链接可以把新闻抓取过来。 遵守robots(标准网络爬虫协议)

12 solr

12.1 solr简介

采用Java开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。

Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http G SolrJ操作提出查找请求,并得到XML格式的返回结果。

12.2 solr与lucene的关系

? Lucene是一套信息检索工具包,但并不包含搜索引擎系统,它包含了索引结构、读

写索引工具、相关性工具、排序等功能,因此在使用Lucene时你仍需要关注搜索引擎系统,例如数据获取、解析、分词等方面的东西。

? 首先Solr是基于Lucene做的 , Solr的目标是打造一款企业级的搜索引擎系统,因

此它更接近于我们认识到的搜索引擎系统,它是一个搜索引擎服务,通过各种API可以让你的应用使用搜索 服务,而不需要将搜索逻辑耦合在应用中。而且Solr可以根据配置文件定义数据解析的方式,更像是一个搜索框架,它也支持主从、热换库等操作。还添加了高亮、facet等搜索引擎常见功能的支持 12.3 solr的搭建运行

? 1、解压solr-4.6.0.zip到你想到存放的路径,比如:e:/solr ? 2、cmd打开命令行窗口,进入E:/solr/example目录 ? 3、执行命令:java -jar start.jar

?

4、通过第三步以后,系统会启动solr自带的jetty服务器,http://localhost:8983/solr/便可访问solr。 ? 此时,solr已成功启动 通过

? 首先Solr是基于Lucene做的 , Solr的目标是打造一款企业级的搜索引擎系统,因

此它更接近于我们认识到的搜索引擎系统,它是一个搜索引擎服务,通过各种API可以让你的应用使用搜索 服务,而不需要将搜索逻辑耦合在应用中。而且Solr可以根据配置文件定义数据解析的方式,更像是一个搜索框架,它也支持主从、热换库等操作。还添加了高亮、facet等搜索引擎常见功能的支持 12.3 solr的搭建运行

? 1、解压solr-4.6.0.zip到你想到存放的路径,比如:e:/solr ? 2、cmd打开命令行窗口,进入E:/solr/example目录 ? 3、执行命令:java -jar start.jar

?

4、通过第三步以后,系统会启动solr自带的jetty服务器,http://localhost:8983/solr/便可访问solr。 ? 此时,solr已成功启动 通过

本文来源:https://www.bwwdw.com/article/yy2o.html

Top