Lucene基础
来源:互联网 发布:办公室 植物 知乎 编辑:程序博客网 时间:2024/05/16 13:46
最近有空就研究研究搜索引擎,写个博客记一下笔记,巩固基础
一.Lucene概述
Lucene是高性能的的信息搜索库,他是一个类库,提供了一套简单而强大的API,我们可以利用它完成文本索引和搜索功能。
Lucene最主要的两个功能是提供建立索引和搜索功能,当然还有好多其他的强大的功能,比如高亮显示等等,我在一本书上看到一个图挺好,照着画个简易版,帮助大家理解:
可以主要的过程是我们先根据具体的需要建立索引,这个过程的实现还是很复杂的,这里建立的索引是一种倒排索引,好在Lucene为我们屏蔽了这一切,提供非常人性化的api,我们直接用就好了。索引建立好了之后,用户搜索的时候输入的内容我们给他封装成一个query对象,根据这个对象,在索引库中搜索然后将搜索结果返回给用户。
二.建立索引
1.如果我们要搜索大量的文件,然后找出其中包含的某个词或短语的文件,初级的方法就是顺序扫描每个文件,这样的效率是很低的,对于大量的文件,我们通常采用倒排索引的办法,看一个图:
我们首先建立针对文本的索引,将文本内容转换能够进行快速搜索的格式,我们可以将索引看做是一种数据结构,通过搜索他我们就能够得到与他关联的全部文章。
2.Lucene文件结构
index:索引 一个索引放在一个文件夹中
segment: 段 一个索引中可以有很多段,段与段之间是独立的,添加新的文档可能产生新的段,不同的段可以合并成一个段
document:文档是创建索引的基本单位,不同的文档保存在不同的段,一个段包含不同的文档
field:域 一个文档包含不同的信息类型
term:词是索引的基本单位,是经过词法分析和语言处理后的数据
3.Lucene建立索引的三个步骤
将原始文档转换成文本,分析文本,将分析好的文本保存到索引中
4.索引过程核心类
先直观感受下他们之间关系:
IndexWriter:写索引,是索引过程的核心组件,这个类负责创建新索引或打开已有索引,或则向索引中添加删除更新被索引文档的信息,他可以对索引文件进行写入,不能读取或搜索索引。
Directory:抽象类,子类负责具体指定索引的存储路径,然后传给indexwriter的构造方法
Analyzer:文本分析器,文本文件被索引之前,需要其处理
Document:为一个包含多个Field对象的容器
Field:包含可能被索引的文本内容的类,每个域包含一个域名和域值
5.demo分析
看了官方给的demo,跟自己写的一比,真的是自愧不如,大神就是大神,下面用大神的代码给出例子
public class IndexFiles { private IndexFiles() { } public static void main(String[] args) { //声明要被索引的文档路径和要建立索引的目录路径 String usage = "java org.apache.lucene.demo.IndexFiles [-index INDEX_PATH] [-docs DOCS_PATH] [-update]\n\nThis indexes the documents in DOCS_PATH, creating a Lucene indexin INDEX_PATH that can be searched with SearchFiles"; String indexPath = "index"; String docsPath = null; //是否新建索引 boolean create = true; //根据用户输入的参数设置路径及建立方式 for(int i = 0; i < args.length; ++i) { if ("-index".equals(args[i])) { indexPath = args[i + 1]; ++i; } else if ("-docs".equals(args[i])) { docsPath = args[i + 1]; ++i; } else if ("-update".equals(args[i])) { create = false; } } //如果文档路径为空,终止程序 if (docsPath == null) { System.err.println("Usage: " + usage); System.exit(1); } //建立文档对象 File docDir = new File(docsPath); //如果文档对象不存在或不可读,终止程序 if (!docDir.exists() || !docDir.canRead()) { System.out.println("Document directory '" + docDir.getAbsolutePath() + "' does not exist or is not readable, please check the path"); System.exit(1); } Date start = new Date(); try { //给出良好的用提示 System.out.println("Indexing to directory '" + indexPath + "'..."); //建立索引 Directory dir = FSDirectory.open(new File(indexPath)); //建立分词器,输入与jar对应的版本,我的jar是新版本所以这里不匹配== Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40); //Indexwriter的配置信息,将分词器传入构造方法中 IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40, analyzer); //根据用户输入的方式设置打开方式 if (create) { iwc.setOpenMode(OpenMode.CREATE); } else { iwc.setOpenMode(OpenMode.CREATE_OR_APPEND); } //建立Indexwriter,需要传入directory 对象和配置信息 IndexWriter writer = new IndexWriter(dir, iwc); //具体创建过程 indexDocs(writer, docDir); //关闭 writer.close(); Date end = new Date(); System.out.println(end.getTime() - start.getTime() + " total milliseconds"); } catch (IOException var12) { System.out.println(" caught a " + var12.getClass() + "\n with message: " + var12.getMessage()); } } static void indexDocs(IndexWriter writer, File file) throws IOException { //判断文档是否可读 if (file.canRead()) { //如果是目录,对里面的文件依次建立索引,迭代调用本方法 if (file.isDirectory()) { String[] files = file.list(); if (files != null) { for(int i = 0; i < files.length; ++i) { indexDocs(writer, new File(file, files[i])); } } } else { FileInputStream fis; try { fis = new FileInputStream(file); } catch (FileNotFoundException var9) { return; } try { //根据具体的需求创建域对象 Document doc = new Document(); Field pathField = new StringField("path", file.getPath(), Store.YES); doc.add(pathField); doc.add(new LongField("modified", file.lastModified(), Store.NO)); doc.add(new TextField("contents", new BufferedReader(new InputStreamReader(fis, "UTF-8")))); //根据具体的打开方式创建或更新 if (writer.getConfig().getOpenMode() == OpenMode.CREATE) { System.out.println("adding " + file); writer.addDocument(doc); } else { System.out.println("updating " + file); writer.updateDocument(new Term("path", file.getPath()), doc); } } finally { fis.close(); } } } }}
就是很简单的建立索引的过程,必要的地方我都写了注释,应该都能看的懂,研读大神的代码还是有收获的:
一般简单的建立索引相信一般人都会写,但是最主要的是程序是否有很强的健壮性,是否有有良好的用户体验,面向对象的编程思想,对后期的维护可拓展性是否良好等等,这些都是需要我们不断加强体会的,针对本demo,多次判断文件是否存在,是否可读,并且根据用户具体的输入来编写不同的建立方式等等,这些都是我们应该学习的,当然这还是需要大量的练习和经验的。所以,特别推荐大家有空多研读现在开源框架等的源码,一定很有收获
三.搜索索引
1.搜索过程核心类
IndexSeacher: 可以看成以只读方式打开索引的类,用于搜索由IndexWriter类创建的索引
Term:搜索功能的基本单元,Term对象包含一对字符串元素:域名和单词
Query:有许多子类,最常用的是TermQuery
TermQuery:最基本的查询类型,用于匹配指定域中包含特定项的文档
TopDocs:是一个简单的指针容器,指针一般指向前N个排名的搜索结果
2.demo
这里我自己写了个简单的例子,很好理解
public class IndexSearchTest { public static void main(String[] argcs){ Directory directory = null; try { //建立索引 directory = FSDirectory.open(new File("D://Lucene/test")); //创建Reader对象 DirectoryReader dReader = DirectoryReader.open(directory); //创建indexSearcher对象 IndexSearcher indexSearcher = new IndexSearcher(dReader); Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); //用queryparser对象解析用户输入的内容 QueryParser queryParser = new QueryParser(Version.LUCENE_43,"content",analyzer); //通过queryparser得到query Query query = queryParser.parse("t"); //获得topdocs对象,这个对象包含得到的结果信息 TopDocs topDocs = indexSearcher.search(query,10); //遍历输出 if(topDocs!=null){ System.out.println("total:"+topDocs.totalHits); for (int i = 0; i <topDocs.scoreDocs.length ; i++) { Document document = indexSearcher.doc(topDocs.scoreDocs[i].doc); System.out.println(document.get("id")); } } directory.close(); dReader.close(); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } }}
- Lucene 基础
- lucene基础
- Lucene 基础
- lucene基础
- lucene基础
- Lucene基础
- lucene基础
- Lucene基础
- Lucene基础排序算法
- Lucene 基础指南
- Lucene 基础指南
- Lucene基础篇总结
- Lucene-基础二
- lucene全文检索基础
- Lucene全文检索基础
- lucene全文检索基础
- Lucene全文检索基础
- Lucene-基础篇
- 密码学复习笔记1【基本概念与传统密码技术】
- 软件测试面试题中的sql题目
- Java设计模式之享元模式
- webpack笔记
- bootstrap介绍:
- Lucene基础
- 使用nginx等反向代理时获取Windows版客户端真实的ip及mac地址
- 测试OpenStack 对IPv6的支持
- 如何将测试刨根问底!
- 音频编解码(1):MPEG1 MP3 系统算法分析
- 陆金所逾期事件:P2P真的是在用投资者的钱来探路
- Windows引导修复
- IBM 联想 DELL HP服务器自动关机|解决办法整理
- Image Super Resolution Using Conventional Neural Network (SRCNN)