Lucene全文检索随笔
Posted lhc-hhh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene全文检索随笔相关的知识,希望对你有一定的参考价值。
一,什么是全文检索
全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。
全文检索(Full-Text Retrieval)以文本作为检索对象,找出含有指定词汇的文本。全面、准确和快速是衡量全文检索系统的关键指标。
关于全文检索,我们要知道:
1,只处理文本。
2,不处理语义。
3,搜索时英文不区分大小写。
4,结果列表有相关度排序。
二、 全文检索与数据库检索的区别
全文检索不同于数据库的SQL查询。(他们所解决的问题不一样,解决的方案也不一样,所以不应进行对比)。在数据库中的搜索就是使用SQL,如:SELECT * FROM t WHERE content like ‘%ant%’。这样会有如下问题:
1、匹配效果:如搜索ant会搜索出planting。这样就会搜出很多无关的信息。
2、相关度排序:查出的结果没有相关度排序,不知道我想要的结果在哪一页。我们在使用百度搜索时,一般不需要翻页,为什么?因为百度做了相关度排序:为每一条结果打一个分数,这条结果越符合搜索条件,得分就越高,叫做相关度得分,结果列表会按照这个分数由高到低排列,所以第1页的结果就是我们最想要的结果。
3、全文检索的速度大大快于SQL的like搜索的速度。这是因为查询方式不同造成的,以查字典举例:数据库的like就是一页一页的翻,一行一行的找,而全文检索是先查目录,得到结果所在的页码,再直接翻到这一页。
三、 全文检索的使用场景
我们使用Lucene,主要是做站内搜索,即对一个系统内的资源进行搜索。如BBS(论坛)、BLOG(博客)中的文章搜索,网上商店中的商品搜索等。使用Lucene的项目有Eclipse,智联招聘,天猫,京东等。一般不做互联网中资源的搜索,因为不易获取与管理海量资源(专业搜索方向的公司除外)
四。
1 <dependency> 2 <groupId>org.apache.lucene</groupId> 3 <artifactId>lucene-core</artifactId> 4 <version>4.4.0</version> 5 </dependency>
(2)创建索引
@Test public void create() throws IOException { //索引库 Directory dir = FSDirectory.open(new File("e:/index")); Analyzer analyzer = new IKAnalyzer();//分词器,常用为IK分词器 //索引写入器的相关配置 IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_44, analyzer); //创建索引写入器 IndexWriter indexWriter = new IndexWriter(dir, conf); //article---->document //field。store yes:保存元数据,通常不想显示详细信息时为no,入:商品详情(一般存入数据 库),文章正文,需要查询数据库而不是查索引库 for (int i=0;i<10;i++) { Document document = new Document(); document.add(new StringField("id", String.valueOf(i), Field.Store.YES)); document.add(new StringField("title", "背影", Field.Store.YES)); document.add(new StringField("author", "朱自清", Field.Store.YES)); document.add(new TextField("content", "你站在这里不要动,我去给你买几个橘子百知教育", Field.Store.YES)); document.add(new StringField("date", "2019-1-2", Field.Store.YES)); indexWriter.addDocument(document); } indexWriter.commit(); indexWriter.close(); }
(3)搜索索引
@Test public void search() throws IOException { Directory directory = FSDirectory.open(new File("e:/index")); IndexReader reader = DirectoryReader.open(directory); IndexSearcher indexSearcher = new IndexSearcher(reader); //第一个参数 搜索的条件 查询出的条数 Query query=new TermQuery(new Term("content","橘子")); TopDocs topDocs = indexSearcher.search(query, 100); //相关度排序 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (int i = 0; i < scoreDocs.length; i++) { ScoreDoc scoreDoc = scoreDocs[i]; int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); System.out.println("this is score"+scoreDoc.score); System.out.println("this is id"+document.get("id")); System.out.println("this is title"+document.get("title")); System.out.println("this is author"+document.get("author")); System.out.println("this is content"+document.get("content")); System.out.println("this is date"+document.get("date")); } }
(4)删除索引
@Test public void test3() throws IOException { Directory dir = FSDirectory.open(new File("e:/index")); Analyzer analyzer = new IKAnalyzer(); IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_44, analyzer); IndexWriter indexWriter = new IndexWriter(dir, conf); // indexWriter.deleteAll(); indexWriter.deleteDocuments(new Term("id", "9")); }
(5)集成web环境
service层调用数据库mapper后,还应为商品创建索引,为了让用户更快的得到响应,可以先执行数据库操作,响应后再创建索引
注意:springboot环境中,配置类中可注入LuceneDao,service层可以直接@Autowired直接注入Dao。如下:
@Configuration public class LuceneConfig { @Bean public LuceneProductDao getLuceneProductDao() { return new LuceneProductDao(); } @Bean public LuceneChapterDao getLuceneChapterDao(){return new LuceneChapterDao();} }
(6)多属性查询
依赖
<!-- https://mvnrepository.com/artifact/com.janeluo/ikanalyzer --> <dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>4.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-highlighter --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>4.4.0</version> </dependency>
在一个项目的章节模块中,前台输入查询内容,后台去索引库执行查询,并将关键字以高亮飘红形式展示在前台的搜索界面,可用以下实现
首先在添加章节时已经创建索引,才可查到
package com.baizhi.lucenedao; import com.baizhi.entity.Chapter; import com.baizhi.util.LuceneUtil; import org.apache.lucene.document.*; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.queryparser.classic.MultiFieldQueryParser; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.search.*; import org.apache.lucene.search.highlight.*; import org.apache.lucene.search.highlight.Scorer; import org.apache.lucene.util.Version; import org.wltea.analyzer.lucene.IKAnalyzer; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class LuceneChapterDao { //创建索引,添加资源时创建 public void createIndex(Chapter chapter) { IndexWriter indexWriter = LuceneUtil.getIndexWriter(); Document docFromPro = getDocFromPro(chapter); try { indexWriter.addDocument(docFromPro); LuceneUtil.commit(indexWriter); } catch (IOException e) { e.printStackTrace(); LuceneUtil.rollback(indexWriter); } } //搜索索引 public List<Chapter> SearcherIndex(String params) { int pageSize = 2;//此处可从前台传入,不应写死 int pageNum = 1; IndexSearcher indexSearcher = LuceneUtil.getIndexSearcher(); List<Chapter> list = null; try { String[] strs = {"title"}; //常用查询 MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_44, strs, new IKAnalyzer()); Query query = multiFieldQueryParser.parse(params); Formatter formatter = new SimplehtmlFormatter("<font color=‘red‘>", "</font>"); Scorer scorer = new QueryScorer(query); Highlighter highlighter = new Highlighter(formatter, scorer); TopDocs topDocs = indexSearcher.search(query, pageNum * pageSize); ScoreDoc[] scoreDocs = topDocs.scoreDocs; list = new ArrayList<>(); for (int i=(pageNum - 1) * pageSize; i < scoreDocs.length; i++) { ScoreDoc scoreDoc = scoreDocs[i]; int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); //高亮开始 try { String bestFragment = highlighter.getBestFragment(new IKAnalyzer(), "title", document.get("title")); if (bestFragment == null) { System.out.println("this is title8" + document.get("id")); } else { System.out.println("this is title9" + bestFragment); //Chapter chapter = getProFromDoc(document); Chapter chapter = new Chapter(); chapter.setTitle(bestFragment); System.out.println(chapter); //存入list list.add(chapter); } // System.out.println("this is id3" + highlighter.getBestFragment(new IKAnalyzer(), "content", document.get("content"))); } catch (InvalidTokenOffsetsException e) { e.printStackTrace(); } } } catch (ParseException e) { e.printStackTrace(); }catch (IOException ee) { ee.printStackTrace(); } return list; } public Document getDocFromPro(Chapter chapter) { Document document = new Document(); // document.add(new StringField("id", chapter.getId()+"", Field.Store.YES)); document.add(new TextField("title", chapter.getTitle(), Field.Store.YES)); return document; } public Chapter getProFromDoc(Document document) { Chapter chapter = new Chapter(); // chapter.setId(document.get("id")); chapter.setTitle(document.get("title")); return chapter; } }
以上是关于Lucene全文检索随笔的主要内容,如果未能解决你的问题,请参考以下文章