Lucene
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene相关的知识,希望对你有一定的参考价值。
Lucene
01.数据的分类
结构化数据:有固定类型或者有固定长度的数据
例如:数据库中的数据(mysql,oracle等), 元数据(就是windows中的数据)
结构化数据搜索方法:
数据库中数据通过sql语句可以搜索
元数据(windows中的)通过windows提供的搜索栏进行搜索
非结构化数据:没有固定类型和固定长度的数据
例如: world文档中的数据, 邮件中的数据
非结构化数据搜索方法:
Word文档使用ctrl+F来搜索
顺序扫描法:
Ctrl+F中是使用的顺序扫描法,拿到搜索的关键字,去文档中,逐字匹配,直到找到和关键字一致的内容为止.
优点: 如果文档中存在要找的关键字就一定能找到想要的内容
缺点: 慢, 效率低
全文检索算法(倒排索引算法):
将文件中的内容提取出来, 将文字拆封成一个一个的词(分词), 将这些词组成索引(字典中的目录), 搜索的时候先搜索索引,通过索引找文档,这个过程就叫做全文检索.
分词: 去掉停用词(a, an, the ,的, 地, 得, 啊, 嗯 ,呵呵),因为搜索的时候搜索这些词没有意义,将句子拆分成词,去掉标点符号和空格
优点: 搜索速度快
缺点: 因为创建的索引需要占用磁盘空间,所以这个算法会使用掉更多的磁盘空间,这是用空间换时间
原理:
相当于字典,分为目录和正文两部分,查询的时候通过先查目录,然后通过目录上标注的页数去正文页查找需要的内容
02.Lucene
什么是lucene
Lucene是apache旗下的顶级项目,是一个全文检索工具包
Lucene就是一个可以创建全文检索引擎系统的一堆jar包.可以使用它来构建全文检索引擎系统,但是它不能独立运
全文检索引擎系统
放在tomcat下可以独立运行,对外提供全文检索服务.
03.Lucene应用领域
1. 互联网全文检索引擎(比如百度, 谷歌, 必应)
2. 站内全文检索引擎(淘宝, 京东搜索功能)
3. 优化数据库查询(因为数据库中使用like关键字是全表扫描也就是顺序扫描算法,查询慢)
Lucene下载
官方网站:http://lucene.apache.org/
版本:lucene4.10.3
Jdk要求:1.7以上
IDE:Eclipse
04.Lucene结构
索引:
域名:词 这样的形式,
它里面有指针执行这个词来源的文档
索引库: 放索引的文件夹(这个文件夹可以自己随意创建,在里面放索引就是索引库)
Term词元: 就是一个词, 是lucene中词的最小单位
文档:
Document对象,一个Document中可以有多个Field域对象,Field域对象中是key value键值对的形式:有域名和域值,
一个document就是数据库表中的一条记录, 一个Filed域对象就是数据库表中的一行一列
这是一个通用的存储结构.
创建索引和所有时所用的分词器必须一致
05.操作_创建索引
/** * 采集文件系统中的文档数据,放入Lucene中 * @throws Exception */ @Test public void testIndexCreate()throws Exception{ List<Document> docList = new ArrayList<Document>(); //指定文件目录 File dir = new File("D:\\searchsource"); //循环文件夹,取出文件 for(File file:dir.listFiles()) { String fileName = file.getName(); String fileContext = FileUtils.readFileToString(file); Long fileSize = FileUtils.sizeOf(file); //文件系统中的一个文件就是一个document对象 Document doc = new Document(); //第一个参数叫做域名,第二个参数叫做域值,第三个参数是否存储,yes/no TextField nameField = new TextField("fileName", fileName,Store.YES); TextField contextField = new TextField("fileContext", fileContext,Store.YES); TextField sizeField = new TextField("fileSize", fileSize.toString(),Store.YES); //将所有的域都存入文档中 doc.add(nameField); doc.add(sizeField); doc.add(contextField); docList.add(doc); } //创建分词器,StandardAnalyzer是一个标准分词器,对英文效果好,对中文单字分词 Analyzer analyzer = new StandardAnalyzer(); //指定索引和文档的目录 //RAMDirectory:内存,FSDirectory:磁盘 Directory directory = FSDirectory.open(new File("D:\\luceneTest")); //创建写对象的初始化对象 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer); //创建索引写对象 IndexWriter indexWriter = new IndexWriter(directory, config); for(Document doc:docList) { indexWriter.addDocument(doc); } //提交 indexWriter.commit(); indexWriter.close(); } }
06.使用Luke查看创建的索引
07.操作_搜索
public class IndexSearchTest { @Test public void testIndexSearch()throws Exception{ //创建分词器:创建索引和搜索时用的分词器一致 Analyzer analyzer = new StandardAnalyzer(); //创建查询对象,第一个参数是默认搜索域,第二个参数是分词器 //默认搜索域的作用:如果搜索语法中指定域名从指定域中搜索,如果搜索时只写了查询关键字,则从默认搜索域中搜索 QueryParser queryParser = new QueryParser("fileContext", analyzer); //查询语法=域名:搜素的关键字 Query query = queryParser.parse("fileName:apache"); //指定索引和文档的目录 Directory dir = FSDirectory.open(new File("D:\\luceneTest")); //创建索引和文档读取对象 IndexReader indexReader = IndexReader.open(dir); //创建索引搜索对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); //第一个参数为查询语句对象,第二为显示的条数 TopDocs topDocs = indexSearcher.search(query, 10); System.out.println("==count==" + topDocs.totalHits); //从搜索结果对象中获取结果集 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for(ScoreDoc scoreDoc:scoreDocs) { //获取docID int docID = scoreDoc.doc; //通过文档ID从硬盘读取出相应的文档 Document document = indexReader.document(docID); //get域名可以取出值打印 System.out.println("fileName" + document.get("fileName")); System.out.println("fileSize" + document.get("fileSize")); System.out.println("==============================="); } } }
注意:Query query = queryParser.parse("fileName:apache");这个语法自己写
08.域的详细介绍
是否分词:
分词的作用是为了索引
需要分词: 文件名称, 文件内容
不需要分词: 不需要索引的域不需要分词,还有就是分词后无意义的域不需要分词
比如: id, ×××号
是否索引:
索引的的目的是为了搜索.
需要搜索的域就一定要创建索引,只有创建了索引才能被搜索出来
不需要搜索的域可以不创建索引
需要索引: 文件名称, 文件内容, id, ×××号等
不需要索引: 比如图片地址不需要创建索引, e:\\xxx.jpg
因为根据图片地址搜索无意义
是否存储:
存储的目的是为了显示.
是否存储看个人需要,存储就是将内容放入Document文档对象中保存出来,会额外占用磁盘空间, 如果搜索的时候需要马上显示出来可以放入document中也就是要存储,这样查询显示速度快, 如果不是马上立刻需要显示出来,则不需要存储,因为额外占用磁盘空间不划算.
域的各种类型
Field类 | 数据类型 | Analyzed 是否分析 | Indexed 是否索引 | Stored 是否存储 | 说明 |
StringField(FieldName, FieldValue,Store.YES)) | 字符串 | N | Y | Y或N | 这个Field用来构建一个字符串Field,但是不会进行分析,会将整个串存储在索引中,比如(订单号,姓名等) 是否存储在文档中用Store.YES或Store.NO决定 |
LongField(FieldName, FieldValue,Store.YES) | Long型 | Y | Y | Y或N | 这个Field用来构建一个Long数字型Field,进行分析和索引,比如(价格) 是否存储在文档中用Store.YES或Store.NO决定 |
StoredField(FieldName, FieldValue) | 重载方法,支持多种类型 | N | N | Y | 这个Field用来构建不同类型Field 不分析,不索引,但要Field存储在文档中 |
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName, reader)
| 字符串 或 流 | Y | Y | Y或N | 如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略. |
注意:lucene底层的算法,钱数是要分词的,因为要根据价钱进行对比
例如: 大于12.5元的小于100元的商品搜索出来
09.中文索引
创建分词器Analyzer analyzer = new IKAnalyzer();
010.操作_索引维护(删除)
@Test public void testIndexDel() throws Exception{ //创建分词器,StandardAnalyzer标准分词器,标准分词器对英文分词效果很好,对中文是单字分词 Analyzer analyzer = new IKAnalyzer(); //指定索引和文档存储的目录 Directory directory = FSDirectory.open(new File("E:\\dic")); //创建写对象的初始化对象 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer); //创建索引和文档写对象 IndexWriter indexWriter = new IndexWriter(directory, config); //删除所有 //indexWriter.deleteAll(); //根据名称进行删除 //Term词元,就是一个词, 第一个参数:域名, 第二个参数:要删除含有此关键词的数据 indexWriter.deleteDocuments(new Term("fileName", "apache")); //提交 indexWriter.commit(); //关闭 indexWriter.close(); |
011.操作_索引维护(更新)
/** * 更新就是按照传入的Term进行搜索,如果找到结果那么删除,将更新的内容重新生成一个Document对象 * 如果没有搜索到结果,那么将更新的内容直接添加一个新的Document对象 * @throws Exception */ @Test public void testIndexUpdate() throws Exception{ //创建分词器,StandardAnalyzer标准分词器,标准分词器对英文分词效果很好,对中文是单字分词 Analyzer analyzer = new IKAnalyzer(); //指定索引和文档存储的目录 Directory directory = FSDirectory.open(new File("E:\\dic")); //创建写对象的初始化对象 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer); //创建索引和文档写对象 IndexWriter indexWriter = new IndexWriter(directory, config); //根据文件名称进行更新 Term term = new Term("fileName", "web"); //更新的对象 Document doc = new Document(); doc.add(new TextField("fileName", "xxxxxx", Store.YES)); doc.add(new TextField("fileContext", "think in java xxxxxxx", Store.NO)); doc.add(new LongField("fileSize", 100L, Store.YES)); //更新 indexWriter.updateDocument(term, doc); //提交 indexWriter.commit(); //关闭 indexWriter.close(); } |
以上是关于Lucene的主要内容,如果未能解决你的问题,请参考以下文章