Lucene全文检索基础

---------------------------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处]
文章出处:http://blog.csdn.net/sdksdk0/article/details/51873672
作者:朱培     ID:sdksdk0

---------------------------------------------------------------------------------------------------------------

我提倡“少理论,少模型”,“多实践”,“多应用”的学习态度,今天带来的是关于站内搜索的基础使用,目前检索这个领域有非常多优秀的框架了,但是身为一个全文检索领域的经典祖先,我们还是需要了解和掌握其精华的。本文主要内容有Lucene简介、索引库的建立、关键字搜索、检索分页、网站排名优化、分词、搜索结果高亮等。要求掌握其基本开发流程,并可以使用servlet+easyUI+lucene+jsp+js等技术做一个简易的站内搜索的功能模块。

一、简介

1.1 简介

Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。

即:Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索。

Lucene只能进行站内搜索。需要有索引库。

1.2 Lucene中存放的内容

Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,

这些内容统称为索引库,索引库有二部份组成:

(1)原始记录

存入到索引库中的原始文本,例如:传智是一家IT培训机构

(2)词汇表

按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表

1.3 传统SQL的缺点

(1)SQL只能针对数据库表存储,不能直接针对硬盘上的文本搜索

(2)SQL没有相关度排名

(3)SQL搜索结果没有关健字高亮显示

(4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle

(5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle

二、创建索引库

2.1 索引库创建

创建索引库:

1) 创建JavaBean对象

2) 创建Docment对象

3) 将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同

4) 创建IndexWriter对象

5) 将Document对象通过IndexWriter对象写入索引库中

6) 关闭IndexWriter对象

开发步骤:

1、新建一个javaweb工程,

  • 导入Lucene相关的jar包
  • lucene-core-3.0.2.jar【Lucene核心】
  • lucene-analyzers-3.0.2.jar【分词器】
  • lucene-highlighter-3.0.2.jar【Lucene会将搜索出来的字,高亮显示,提示用户】
  • lucene-memory-3.0.2.jar【索引库优化策略】

然后可以写javaBean对象,Article.java

private  Integer id;  //索引号
	private  String title; //标题
	private  String content;  //内容

get ,set方法,还有toString一下,有参和无参构造函数都要加上。

2、在demo1中邪一个方法,createIndexDB()

public void createIndexDB() throws IOException{
		//创建article对象
		Article  at=new Article(1, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包");
		//创建Document对象
		Document doc=new Document();
		//将article对象中的3个属性分别绑定到document对象中

		/*
		 *
		 * 参数1:document对象中的属性名叫xid,article对象中的属性名叫id
		 * 参数2:document对象中的xid的值,与article对象中相同
		 * 参数3:是否将xid属性值存入词汇表,YES表示会存入,NO表示不会存入
		 * 参数4:是否将xid属性值进行分词,ANALYZED表示会进行词汇拆分 ,NOT_ANALYZED不会进行拆分
		 *
		 * 项目中提倡非id值进行词汇拆分,提倡非id值存入词汇表
		 */

		doc.add(new Field("xid",at.getId().toString(),Store.YES,Index.ANALYZED));
		doc.add(new Field("xtitle",at.getTitle().toString(),Store.YES,Index.ANALYZED));
		doc.add(new Field("xcontent",at.getContent().toString(),Store.YES,Index.ANALYZED));

		//将document对象写入lucene索引库
		/*
		 * 参数1:lucene索引库最终对应于硬盘中的目录
		 * 参数2:将文本拆分的策略,一个策略就是一个具体的实现类
		 * 参数3:最多将文本拆分的词汇,LIMITED表示1万个,只取前1万个
		 *
		 */
		Directory d=FSDirectory.open(new File("D:/IndexDB"));
		Analyzer a=new StandardAnalyzer(Version.LUCENE_30);
		MaxFieldLength mfl=MaxFieldLength.LIMITED;

		IndexWriter iw=new IndexWriter(d, a, mfl);
		iw.addDocument(doc);
		//关闭字符流对象
		iw.close();

	}

2.2工具类创建

我们发现以上方法创建索引比较麻烦,所以我们可以封装一下,新建一个工具类LuceneUtil.java,在这个类中把以下四个内容进行封装,各自取get,set方法。

	private static Directory d;  //索引库存放的目录
	private static Version version;  //版本号
	private static Analyzer analyzer;  //词汇拆分的策略
	private static  MaxFieldLength mfl;  //最大分词数

用静态块来防止外界new该帮助类;

//防止外界new该帮助类
	static{
		try {
			d=FSDirectory.open(new File("D:/IndexDB"));
			version=Version.LUCENE_30;
			analyzer=new StandardAnalyzer(version);
			mfl=MaxFieldLength.LIMITED;
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

	}

将需要的对象进行封装:

//将javabean转成document对象
	public static Document javabean2Document(Object obj) throws Exception{

		Document document=new Document();

		//获取obj引用的对象字节码
		Class  clazz=obj.getClass();
		java.lang.reflect.Field[] reflectFields=clazz.getDeclaredFields();
		//迭代
		for(java.lang.reflect.Field reflectField:reflectFields){
			//反射
			reflectField.setAccessible(true);
			//获取属性名,
			String name=reflectField.getName();
			String methodName="get"+name.substring(0,1).toUpperCase()+name.substring(1);
			//获取方法
			Method method=clazz.getMethod(methodName, null);
			//执行方法
			String value=method.invoke(obj, null).toString();
			//加入到document对象中去
			document.add(new Field(name,value,Store.YES,Index.ANALYZED));

		}
		//返回document对象
		return document;
	}
	//将document转成avabean对象
	public static Object document2Javabean(Document document, Class clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException{
		Object obj=clazz.newInstance();

		java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
		for(java.lang.reflect.Field field : reflectFields){
			field.setAccessible(true);
			String name= field.getName();
			String value = document.get(name);
			BeanUtils.setProperty(obj,name,value);
		}	

		return obj;

	}

2.3 使用工具类对索引库的增删改

以上步骤都完成后,就可以直接用工具类来对索引库进行操作了

创建单个索引库

@Test
	//创建索引库
     public void createIndexDB() throws Exception{
    	 Article  at=new Article(1, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包");
 		//创建Document对象
 		Document doc=LuceneUtil.javabean2Document(at);
    	IndexWriter iw=new IndexWriter(LuceneUtil.getD(), LuceneUtil.getAnalyzer(), LuceneUtil.getMfl()) ;
    	iw.addDocument(doc);
    	iw.close();
     }

创建多个索引对象

	@Test
	public void addAll() throws Exception{
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(), LuceneUtil.getAnalyzer(), LuceneUtil.getMfl()); 

		Article  at1=new Article(1, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包");
		Document document1=LuceneUtil.javabean2Document(at1);
		iw.addDocument(document1);

		Article  at2=new Article(2, "lucene","Lucene是根据关健字来搜索的文本搜索工具");
		Document document2=LuceneUtil.javabean2Document(at2);
		iw.addDocument(document2);

		Article  at3=new Article(3, "lucene","Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的");
		Document document3=LuceneUtil.javabean2Document(at3);
		iw.addDocument(document3);

		Article  at4=new Article(4, "lucene","Lucene它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引");
		Document document4=LuceneUtil.javabean2Document(at4);
		iw.addDocument(document4);

		iw.close();

	}

修改索引、

	@Test
	public void update() throws Exception{
		Article  newArticle=new Article(4, "lucene","4是一个全文检索引擎的架构,提供了完整的创建索引和查询索引");
		Document document=LuceneUtil.javabean2Document(newArticle);
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(), LuceneUtil.getAnalyzer(), LuceneUtil.getMfl()); 

		iw.updateDocument(new Term("id","4"), document);
		iw.close();
	}

查询:

	@Test
	public void findAll() throws Exception{
		String keywords="是";
		List<Article> atl=new ArrayList<Article>();

		QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
		Query query=queryParser.parse(keywords);
		IndexSearcher  is=new IndexSearcher(LuceneUtil.getD());
		TopDocs td=is.search(query,100);

		for(int i=0;i<td.scoreDocs.length;i++){
			ScoreDoc sd=td.scoreDocs[i];

			int no=sd.doc;
			Document document=is.doc(no);
			Article article=(Article) LuceneUtil.document2Javabean(document, Article.class);
			atl.add(article);

		}
		for (Article article : atl) {
			System.out.println(article);
		}
	}

删除

	@Test
	public void delete() throws  LockObtainFailedException, IOException{
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(), LuceneUtil.getAnalyzer(), LuceneUtil.getMfl()); 

		iw.deleteDocuments(new Term("id","2"));
		iw.close();
	}

	public void deleteAll() throws CorruptIndexException, LockObtainFailedException, IOException{
		IndexWriter indexWriter = new IndexWriter(LuceneUtil.getD(),LuceneUtil.getAnalyzer(),LuceneUtil.getMfl());
		indexWriter.deleteAll();
		indexWriter.close();

	}

三、关键字搜索

根据关键字查询索引库中的内容:

1) 创建IndexSearcher对象

2) 创建QueryParser对象

3) 创建Query对象来封装关键字

4) 用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准

5) 获取符合条件的编号

6) 用indexSearcher对象去索引库中查询编号对应的Document对象

7) 将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用

传统的搜索方式:

/**
	 * 根据关键字从索引库中搜索符合条件的记录
	 *
	 * @throws IOException
	 * @throws ParseException
	 *
	 */
	@Test
	public void findIndexDB() throws IOException, ParseException{
		//搜索"源"这个字
		String keyword="apache";
		List<Article>  atl=new ArrayList<Article>();

		Directory d=FSDirectory.open(new File("D:/IndexDB"));
		Analyzer a=new StandardAnalyzer(Version.LUCENE_30);
		MaxFieldLength mfl=MaxFieldLength.LIMITED;

		//创建IndexSearch字符流对象
		IndexSearcher  is=new IndexSearcher(d);

		/*
		 * 参数1:使用分词器的版本,qitqt
		 * 参数2:针对document对象中的哪个属性进行搜索
		 */
		Version version=Version.LUCENE_30;
		Analyzer analyzer=new StandardAnalyzer(version);
		QueryParser queryParser=new QueryParser(version,"xcontent",analyzer);
		//封装查询关键字
		Query query=queryParser.parse(keyword);
		/*
		 * 参数1:查询对象及封装关键字的对象
		 * 参数2:MAX_RECORD表示如果根据关键字搜索出来的内容教多,只取前MAX_RECORD个
		 *
		 */
		int MAX_RECORD=100;
		TopDocs td=is.search(query,MAX_RECORD);
		//迭代词汇表中符合条件的编号
		for(int i=0;i<td.scoreDocs.length;i++){
			//取出每一个编号和分数scoreDoc对象
			ScoreDoc scoreDoc=td.scoreDocs[i];
			//取出每一个编号
			int no=scoreDoc.doc;
			//根据编号去索引库中的原始记录表中查询对应的document对象
			Document document=is.doc(no);
			String xid=document.get("xid");
			String xtitle=document.get("xtitle");
			String xcontent=document.get("xcontent");
			//封装到article对象中
			Article article=new Article(Integer.parseInt(xid),xtitle,xcontent);
			//将article对象加入到list集合中
			atl.add(article);

		}
		//迭代结果集
		for(Article a1:atl){
			System.out.println(a1);
		}
	}

使用工具类:其实就是前面那一节里面的查询。

//根据关键字查询
	@Test
	public void findIndexDB() throws Exception {
		String keywords="是";
		List<Article> atl=new ArrayList<Article>();

		QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
		Query query=queryParser.parse(keywords);
		IndexSearcher  is=new IndexSearcher(LuceneUtil.getD());
		TopDocs td=is.search(query,100);

		for(int i=0;i<td.scoreDocs.length;i++){
			ScoreDoc sd=td.scoreDocs[i];

			int no=sd.doc;
			Document document=is.doc(no);
			Article article=(Article) LuceneUtil.document2Javabean(document, Article.class);
			atl.add(article);

		}
		for (Article article : atl) {
			System.out.println(article);
		}

	}

单字段和多字段的搜索

单字段:

QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());

多字段

QueryParser queryParser = new MultiF

搜索结果高亮显示

//格式对象
    Formatter formatter = new SimpleHTMLFormatter("<font color=‘red‘>","</font>");
    //关键字对象
    Scorer scorer = new QueryScorer(query);
    //高亮对象
    Highlighter highlighter = new Highlighter(formatter,scorer);


四、分词器

采用一种算法,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索

使用分词器的原因

 因为用户输入的搜索的内容是一段文本中的一个关健字,和原始表中的内容有差别,
 但作为搜索引擎来讲,又得将相关的内容搜索出来,此时就得采用分词器来最大限度
 匹配原始表中的内容

分词器工作流程

 步一:按分词器拆分出词汇
 步二:去除停用词和禁用词
 步三:如果有英文,把英文字母转为小写,即搜索不分大小写
//测试Lucene内置和第三方分词器的分词效果
public class TestAnalyzer {

	private static void testAnalyzer(Analyzer analyzer, String text) throws Exception {
		System.out.println("当前使用的分词器:" + analyzer.getClass());
		TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));
		tokenStream.addAttribute(TermAttribute.class);
		while (tokenStream.incrementToken()) {
			TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
			System.out.println(termAttribute.term());
		}
	}

	public static void main(String[] args) throws Exception {
		testAnalyzer(new StandardAnalyzer(LuceneUtil.getVersion()), "采用一种算法aa,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索");
		testAnalyzer(new FrenchAnalyzer(LuceneUtil.getVersion()), "采用一种算法aa,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索");
		testAnalyzer(new CJKAnalyzer(LuceneUtil.getVersion()), "采用一种算法aa,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索");
		testAnalyzer(new IKAnalyzer(), "指令汇科技实业呀");

	}

}

IK分词器

testAnalyzer(new IKAnalyzer(), "指令汇科技实业呀");

导入IKAnalyzer分词器核心jar包,IKAnalyzer3.2.0Stable.jar

将IKAnalyzer.cfg.xml和stopword.dic和mydict.dic文件复制到MyEclipse的src目录下, 再进行配置,在配置时,首行需要一个空行。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>

	<!-- 用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">/mydict.dic</entry> 

	<!--用户可以在这里配置自己的扩展停止词字典 -->
	<entry key="ext_stopwords">/surname.dic</entry> 

</properties>

mydict.dic内容如下:首行空出来:

指令汇科技

stopword.dic内容如下,首行空出来



五、搜索排名优化

5.1 索引库优化

//设置合并因子,即满足3个cfs文件合并 iw.addDocument(doc); iw.setMergeFactor(3);

索引库 内存索引库 硬盘索引库

//合并.cfs文件,解决文件的大小和数量问题
	@Test
	public void type1() throws Exception{
		Article  at=new Article(1, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",10);
		//创建Document对象
		Document doc=LuceneUtil.javabean2Document(at);
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(),LuceneUtil.getAnalyzer(),LuceneUtil.getMfl());
		iw.optimize();
		iw.close();
	}

	//合并.cfs文件,解决文件的大小和数量问题
	@Test
	public void type2() throws Exception{
		Article  at=new Article(2, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",10);
		//创建Document对象
		Document doc=LuceneUtil.javabean2Document(at);
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(),LuceneUtil.getAnalyzer(),LuceneUtil.getMfl());

		//设置合并因子,即满足3个cfs文件合并
		iw.addDocument(doc);
		iw.setMergeFactor(3);
		iw.close();
	}*/

	//合并.cfs文件,解决文件的大小和数量问题
	@Test
	public void type4() throws Exception{
		Article  at=new Article(2, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",10);
		Document doc=LuceneUtil.javabean2Document(at);

		//硬盘索引库
		Directory fsDirectory=FSDirectory.open(new File("D:/IndexDB"));

		//内存索引库
		Directory ramDirectory=new RAMDirectory(fsDirectory);

		//指向硬盘索引库的字符流,true表示如果内存索引库中和硬盘索引库中有系统的document对象时,先删除硬盘索引库的值
		IndexWriter fsIw=new IndexWriter(fsDirectory,LuceneUtil.getAnalyzer(),true,LuceneUtil.getMfl());

		//指向内存索引库的字符流
		IndexWriter ramIw=new IndexWriter(ramDirectory,LuceneUtil.getAnalyzer(),LuceneUtil.getMfl());

		//将document对象写入内存索引库
		ramIw.addDocument(doc);
		ramIw.close();

		//将内存索引库中所有的document对象同步到硬盘索引中
		fsIw.addIndexesNoOptimize(ramDirectory);
		fsIw.close();
	}
	

5.2 相关度得分排序

Lucene中的显示结果次序与相关度得分有关 ScoreDoc.score; 默认情况下,Lucene是按相关度得分排序的,得分高排在前,得分低排在后 如果相关度得分相同,按插入索引库的先后次序排序。

	//增加document对象索引库中
	@Test
	public void add() throws Exception{
		//Article  at=new Article(1, "lucene","Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",10);
		//Article  at=new Article(2, "lucene2","Lucene2是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",20);
		Article  at=new Article(3, "新lucene3","Lucene3是apache软件基金会发布的一个开放源代码的全文检索引擎工具包",30);
		//Article  at=new Article(4, "lucene4","Lucene4是是软件基金会发布是时的一个开放源是代码的全文是检索引擎是工具包",30);
		//Article  at=new Article(5, "lucene5","是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是是",30);

		//创建Document对象
		Document doc=LuceneUtil.javabean2Document(at);
		IndexWriter  iw=new IndexWriter(LuceneUtil.getD(),LuceneUtil.getAnalyzer(),LuceneUtil.getMfl());
		doc.setBoost(20F);
		iw.addDocument(doc);
		iw.close();
	}
	
//获取document对象的评分
        float score=sd.score;

强行提高得分 doc.setBoost(100F);  搜索结果是按某个或某些字段高低排序来显示的结果.

5.3 字段排序

按单个字段排序

//创建排序的条件
		/*
		 * 参数1:id表示依据document对象中的那个字段排序,里如id
		 * 参数2:sortField.INT表示document对象中该字段的类型,
		 * 参数3:true表示降序,类似于order by
		 *
		 *
		 */
		Sort sort=new Sort(new SortField("id",SortField.INT,true));
		TopDocs td=is.search(query, null,100,sort);

按多个字段排序

//创建排序的条件
		/*
		 * 参数1:id表示依据document对象中的那个字段排序,里如id
		 * 参数2:sortField.INT表示document对象中该字段的类型,
		 * 参数3:true表示降序,类似于order by
		 *
		 *
		 */
		Sort sort=new Sort(
				new SortField("count",SortField.INT,true),
				new SortField("count",SortField.INT,true ));
		TopDocs td=is.search(query, null,100,sort);

六、分页(实现站内搜索功能)

6.1 Bean

同之前的Artucle.java

private  Integer id;  //索引号
	private  String title; //标题
	private  String content;  //内容

get ,set方法,还有toString一下,有参和无参构造函数都要加上。

同时还要一个分页的bean,进行封装

private Integer currPageNO;//当前页号
	private Integer perPageSize = 3;//每页显示记录数,默认为2条
	private Integer allRecordNO;//总记录数OK
	private Integer allPageNO;//总页数OK
	private List<Article> articleList = new ArrayList<Article>();//内容

get ,set方法,还有toString一下,有参和无参构造函数都要加上。

6.2 持久层

新建ArticleDao.java

//根据关键字,获取总记录数,返回总的记录数

	public int getAllRecord(String keywords) throws Exception{
		List<Article> atl=new ArrayList<Article>();

		QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
		Query query=queryParser.parse(keywords);
		IndexSearcher  is=new IndexSearcher(LuceneUtil.getD());
		TopDocs td=is.search(query,5);

		//返回符合条件的真实总记录数,不受search(query,5)中定义的5的影响
		//return td.totalHits;  //17条
		return td.scoreDocs.length;   //5条

	}

	//根据关键字,批量查询记录
	/*
	 * start:从第几条记录的索引号开始查询,索引号从0开始
	 * size:最多查询几条记录,不满足最多数目时,以实际为准
	 * 返回集合
	 */
	public List<Article>  findAll(String keywords,int start,int size) throws Exception{
		List<Article>  atl=new ArrayList<Article>();
		QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
		Query query=queryParser.parse(keywords);
		IndexSearcher  is=new IndexSearcher(LuceneUtil.getD());
		TopDocs td=is.search(query,100);

		int middle=Math.min(start+size,td.totalHits);
		for(int i=start;i<middle;i++){
			ScoreDoc  sd=td.scoreDocs[i];
			int no=sd.doc;
			Document document=is.doc(no);
			Article at=(Article) LuceneUtil.document2Javabean(document, Article.class);
			atl.add(at);
		}
		return atl;

	}

6.3、业务层

新建一个ArticleService.java ,对分页进行处理

private ArticleDao  articleDao=new ArticleDao();

	//根据关键字和页号,查询内容
	public PageBean show(String keywords,int currPageNO) throws Exception{

		PageBean page=new PageBean();
		//封装当前页号
		page.setCurrPageNO(currPageNO);

		//封装总记录数
		int allRecordNO=articleDao.getAllRecord(keywords);
		page.setAllRecordNO(allRecordNO);

		//封装总页数
		int allPageNO=0;
		if(page.getAllRecordNO() % page.getPerPageSize() ==0){
			allPageNO=page.getAllRecordNO() / page.getPerPageSize();
		}else{
			allPageNO=page.getAllRecordNO() /page.getPerPageSize()+1;
		}
		page.setAllPageNO(allPageNO);

		//封装内容
		int size=page.getPerPageSize();
		int start=(page.getCurrPageNO()-1)*size;
		List<Article>  art=articleDao.findAll(keywords, start, size)	;
		page.setArticleList(art);
		return page;

	}

6.4、控制器

使用一个servlet来对数据进行控制。doGet和doPost方法中进行处理。

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		try {
		//获取关键字
		String keywords=request.getParameter("keywords");
		if(keywords==null || keywords.trim().length()==0){
			keywords="是";
		}
		//获取当前页号
		String temp=request.getParameter("page");
		if(temp==null || temp.trim().length()==0){
			temp="1";
		}
		//调用业务层
		ArticleService articleService=new ArticleService();
		PageBean page=articleService.show(keywords,Integer.parseInt(temp));

		//构造map对象
		Map<String,Object> map=new LinkedHashMap<String, Object>();
		map.put("total", page.getAllPageNO());
		map.put("rows", page.getArticleList());

		//将map转成json
		JSONArray  jsonArray=JSONArray.fromObject(map);
		String jsonJAVA=jsonArray.toString();
		//去掉两边的[]符号
		jsonJAVA=jsonJAVA.substring(1,jsonJAVA.length()-1);

		//以流的方式将json文本输出到DateGrid组件中
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter pw=response.getWriter();
		pw.write(jsonJAVA);
		pw.flush();
		pw.close();

		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

	}

6.5 视图(界面处理)

我们使用一个jsp来书写界面。先把我们需要的js包,jquery,easyui相关的jar导入到项目的lib目录中,然后在这个jsp文件中引入我们所需要的文件。命名为list.jsp.

<!-- 引入css文件,无顺序 -->
    <link rel="stylesheet" href="themes/icon.css" type="text/css"></link>
    <link rel="stylesheet" href="themes/default/easyui.css" type="text/css"></link>
  	<!-- 引入js文件,有顺序 -->
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/jquery.easyui.min.js"></script>
	<script type="text/javascript" src="js/easyui-lang-zh_CN.js"></script>

在这里就暂时假设你已经学会使用easyui了,如果对使用easyui还有什么问题的,欢迎查看我的下一篇文章。

<!-- 输入区 -->
	<form id="myformID">
		输入关键字:<input type="text" value="" id="keywordID"/>
		<input type="button" value="站内搜索" id="findID"/>
	</form>
	<script type="text/javascript">
		//定位"站内搜索"按钮
		$("#findID").click(function(){
			//获取关键字
			var keyword = $("#keywordID").val();
			//去空格
			keyword = $.trim(keyword);
			//判断
			if(keyword.length == 0){
				//提示
				alert("请输入关键字!!!");
				//清空文本框的内容
				$("#keywordID").val("");
				//定位于输入关键字文本框
				$("#keywordID").focus();
			}else{
				//异步发送请求到服务器
				//load表示方法名
				//"keywords"表示需要发送的的参数名,后台收:request.getParameter("keywords")
				//keyword表示参数值
				$("#dg").datagrid("load",{
				    "keywords" : keyword
				});
			}
		});
	</script>

	<!-- 显示区 -->
	<table id="dg"></table>
	<script type="text/javascript">
		$("#dg").datagrid({
			url : "${pageContext.request.contextPath}/servlet/ArticleServlet?time="+new Date().getTime(),
			columns :  [[
					        	{field:‘id‘,title:‘编号‘,width:100},
					        	{field:‘title‘,title:‘标题‘,width:100},
					        	{field:‘content‘,title:‘内容‘,width:100}
						]],
			fitColumns : true,
			singleSelect : true,
			pagination : true,
			pageSize : 2,
			pageList : [2]
		});
	</script>

界面效果如下。

源码下载地址:https://github.com/sdksdk0/lucene  (基础部分,前两章节)

https://github.com/sdksdk0/lucene2  (应用部分,后四章节的内容)

小结:这里对于lucene的使用都是比较基础的部分,重要的要是学会基本的编码流程,开发思想,学以致用,做一个有思想有深度的人,不要变成一个只会敲代码的机器。

时间: 2024-10-14 00:26:47

Lucene全文检索基础的相关文章

jQuery、HTML5、Spring Security安全权限、Lucene全文检索

获取[下载地址]   QQ: 313596790   [免费支持更新]支持三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]A 代码生成器(开发利器);      增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid

Spring MVC、Mybatis、Hibernate、Bootstrap、jQuery、HTML5、Spring Security安全权限、Lucene全文检索、Ehcache分布式缓存 、高性能、高并发【Java企业通用开发平台框架】

获取[下载地址]   QQ: 313596790   [免费支持更新] A 代码生成器(开发利器);    B 阿里巴巴数据库连接池druid;   数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势 C 安全权限框架shiro ;  D ehcache 自定义二级缓存; E 微信接口开发(后续会加入Activiti5 工作流 )免费升级 -------------------------------------------------------

Lucene 全文检索入门

博客地址:http://www.moonxy.com 一.前言 Lucene 是 apache 软件基金会的一个子项目,由 Doug Cutting 开发,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的库,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言).Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎.Lucene 是一套用于全文

Lucene全文检索

 全文检索(Full-Text Retrieval)是指以文本作为检索对象,找出含有指定词汇的文本.全面.准确和快速是衡量全文检索系统的关键指标. l关于全文检索,我们要知道: 1,只处理文本. 2,不处理语义. 3,搜索时英文不区分大小写. 4,结果列表有相关度排序. l在信息检索工具中,全文检索是最具通用性和实用性的. Lucene全文检索

全文检索基础

一.全文检索基础 1.信息源 --> 分词器 --> 建立索引库 2.文本在建立索引和搜索的时候,都会先进行分词 3.索引库的结构 索引表:存放具体词汇,哪些词汇在哪些文档里面存储.索引表里面存储的就是分词器分词之后的结果 数据源:文本信息集合 4.用户搜索时,首先经过分词器进行分词,然后去索引表里面查找对应的词汇( 利用倒排序索引算法 ),再找到对应的文档集合 5.信息集合里每一条数据都是一个 document ( 存储所有信息,他是一个 Field 属性的集合 ) 6.sorre 是否进行

Lucene全文检索之-Lucene基础

Lucene是全文检索引擎 一.在学习Lucene之前我们先思考下,Lucene存在的意义. 1.在之前我们的应用场景中,基于数据库的检索,我们使用like语法进行.但是基于like语法效率低下.达不到我们对应用的使用要求. 而使用Lucene对我们的数据建立索引效率高速度快,满足企业要求. 我们使用Lucene先对整个结构建立索引库,然后根据索引去查找我们需要匹配的内容,效率高速度快,方便我们快速检索信息-这也是Lucene存在的目的. 2.有些查找数据库做不了,比如我们想查找附件中内容的匹配

【Lucene】Apache Lucene全文检索引擎架构之入门实战

Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供.Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻.在Java开发环境里Lucene是一个成熟的免费开源工具.就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库.--<百度百科> 这篇博文主要从两个方面出发,首先介绍一下Lucene中的全文搜索原理,其次通过程序示例来展现如何使用Lucene.关于全文搜索原理部分我上网搜索了一下,也看了好几篇文章,最后在写这篇文

lucene全文检索技术

1:lucene的介绍 全文检索引擎工具包.作用:使用lucene进行全文检索 .可以直接运行. 什么是全文检索.全文检索的场景,搜索引擎,搜索商品. 站内搜索,只会搜索自己站内的资源 全文检索首先将要查询的目标文档中的词提取出来,组成索引,通过查询索引达到搜索的文档的目的 这种先建立索引,在对索引进行搜索的过程就叫全文检索. 索引就类似于书籍的目录,目标文档就相当于书籍中的内容 搜索书籍中的内容,如果不通过目录,很费劲 其实,全文检索就是相当于给书籍编写目录. 2:Lucene实现全文检索的流

Lucene入门——基础知识

Lucene简介 Lucene是一个基于Java的全文信息检索工具包,为应用程序提供索引和搜索功能. Lucene采用的是一种称为反向索引(inverted index)的机制.反向索引就是说我们维护一个词/短语表,对于这个词/短语表再通过一个链表标示哪些文档包含了这个词.短语.这样在用户输入查询条件的时候,就能非常快的查找到搜索结果.对文档建好索引后,可以基于索引进行搜索.搜索引擎首先会对搜索的关键词进行解析,然后再在建立好的索引上查找,最终返回和用户输入的关键词相关联的文档. Lucene软