Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的建立索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础创建起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,如今不少检索引擎都是在其基础上建立的,思想是相通的。java
Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索程序员
既然谈到了网站内部的搜索,那么咱们就谈谈咱们熟悉的百度、google那些搜索引擎又是基于什么搜索的呢….算法
从图上已经看得很清楚,baidu、google等搜索引擎实际上是经过网络爬虫的程序来进行搜索的…数据库
在介绍Lucene的时候,咱们已经说了:Lucene又不是搜索引擎,仅仅是在网站内部进行文本的搜索。那咱们为何要学他呢???apache
咱们以前编写纳税服务系统的时候,其实就已经使用过SQL来进行站内的搜索..markdown
既然SQL能作的功能,咱们还要学Lucene,为何呢???网络
咱们来看看咱们用SQL来搜索的话,有什么缺点:架构
咱们来看看在baidu中搜索Lucene为关键字搜索出的内容是怎么样的:工具
以上所说的,咱们若是使用SQL的话,是作不到的。所以咱们就学习Lucene来帮咱们在站内根据文本关键字来进行搜索数据!学习
咱们若是网站须要根据关键字来进行搜索,可使用SQL,也可使用Lucene…那么咱们Lucene和SQL是同样的,都是在持久层中编写代码的。。
接下来,咱们就讲解怎么使用Lucene了…..在讲解Lucene的API以前,咱们首先来说讲Lucene存放的到底是什么内容…咱们的SQL使用的是数据库中的内存,在硬盘中为DBF文件…那么咱们Lucene内部又是什么东西呢??
Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
这些内容统称为索引库,索引库有二部份组成:
也就是说:Lucene存放数据的地方咱们一般称之为索引库,索引库又分为两部分组成:原始记录和词汇表….
当咱们想要把数据存到索引库的时候,咱们首先存入的是将数据存到原始记录上面去….
又因为咱们给用户使用的时候,用户使用的是关键字来进行查询咱们的具体记录。所以,咱们须要把咱们原始存进的数据进行拆分!将拆分出来的数据存进词汇表中。
词汇表就是相似于咱们在学Oracle中的索引表,拆分的时候会给出对应的索引值。
一旦用户根据关键字来进行搜索,那么程序就先去查询词汇表中有没有该关键字,若是有该关键字就定位到原始记录表中,将符合条件的原始记录返回给用户查看。
咱们查看如下的图方便理解:
到了这里,有人可能就会疑问:难道原始记录拆分的数据都是一个一个汉字进行拆分的吗??而后在词汇表中不就有不少的关键字了???
其实,咱们在存到原始记录表中的时候,能够指定咱们使用哪一种算法来将数据拆分,存到词汇表中…..咱们的图是Lucene的标准分词算法,一个一个汉字进行拆分。咱们可使用别的分词算法,两个两个拆分或者其余的算法。
首先,咱们来导入Lucene的必要开发包:
建立User对象,User对象封装了数据….
/** * Created by ozc on 2017/7/12. */ public class User { private String id ; private String userName; private String sal; public User() { } public User(String id, String userName, String sal) { this.id = id; this.userName = userName; this.sal = sal; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSal() { return sal; } public void setSal(String sal) { this.sal = sal; } }
咱们想要使用Lucene来查询出站内的数据,首先咱们得要有个索引库吧!因而咱们先建立索引库,将咱们的数据存到索引库中。
建立索引库的步骤:
@Test public void createIndexDB() throws Exception { //把数据填充到JavaBean对象中 User user = new User("1", "钟福成", "将来的程序员"); //建立Document对象【导入的是Lucene包下的Document对象】 Document document = new Document(); //将JavaBean对象全部的属性值,均放到Document对象中去,属性名能够和JavaBean相同或不一样 /** * 向Document对象加入一个字段 * 参数一:字段的关键字 * 参数二:字符的值 * 参数三:是否要存储到原始记录表中 * YES表示是 * NO表示否 * 参数四:是否须要将存储的数据拆分到词汇表中 * ANALYZED表示拆分 * NOT_ANALYZED表示不拆分 * * */ document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED)); //建立IndexWriter对象 //目录指定为E:/createIndexDB Directory directory = FSDirectory.open(new File("E:/createIndexDB")); //使用标准的分词算法对原始记录表进行拆分 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); //LIMITED默认是1W个 IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED; /** * IndexWriter将咱们的document对象写到硬盘中 * * 参数一:Directory d,写到硬盘中的目录路径是什么 * 参数二:Analyzer a, 以何种算法来对document中的原始记录表数据进行拆分红词汇表 * 参数三:MaxFieldLength mfl 最多将文本拆分出多少个词汇 * * */ IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength); //将Document对象经过IndexWriter对象写入索引库中 indexWriter.addDocument(document); //关闭IndexWriter对象 indexWriter.close(); }
程序执行完,咱们就会在硬盘中见到咱们的索引库。
那咱们如今是不知道记录是否真真正正存储到索引库中的,由于咱们看不见。索引库存放的数据放在cfs文件下,咱们也是不能打开cfs文件的。
因而,咱们如今用一个关键字,把索引库的数据读取。看看读取数据是否成功。
根据关键字查询索引库中的内容:
@Test public void findIndexDB() throws Exception { /** * 参数一: IndexSearcher(Directory path)查询以xxx目录的索引库 * * */ Directory directory = FSDirectory.open(new File("E:/createIndexDB")); //建立IndexSearcher对象 IndexSearcher indexSearcher = new IndexSearcher(directory); //建立QueryParser对象 /** * 参数一: Version matchVersion 版本号【和上面是同样的】 * 参数二:String f,【要查询的字段】 * 参数三:Analyzer a【使用的拆词算法】 * */ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", analyzer); //给出要查询的关键字 String keyWords = "钟"; //建立Query对象来封装关键字 Query query = queryParser.parse(keyWords); //用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准 TopDocs topDocs = indexSearcher.search(query, 100); //获取符合条件的编号 for (int i = 0; i < topDocs.scoreDocs.length; i++) { ScoreDoc scoreDoc = topDocs.scoreDocs[i]; int no = scoreDoc.doc; //用indexSearcher对象去索引库中查询编号对应的Document对象 Document document = indexSearcher.doc(no); //将Document对象中的全部属性取出,再封装回JavaBean对象中去 String id = document.get("id"); String userName = document.get("userName"); String sal = document.get("sal"); User user = new User(id, userName, sal); System.out.println(user); }
效果:
咱们的Lucene程序就是大概这么一个思路:将JavaBean对象封装到Document对象中,而后经过IndexWriter把document写入到索引库中。当用户须要查询的时候,就使用IndexSearcher从索引库中读取数据,找到对应的Document对象,从而解析里边的内容,再封装到JavaBean对象中让咱们使用。