Lucene系列:(10)多条件搜索 QueryParser

1、什么是条件搜索

用关健字与指定的单列或多例进行匹配的搜索

2、单字段条件搜索

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

3、多字段条件搜索,项目中提倡多字段搜索

QueryParser queryParser = new MultiFieldQueryParser(LuceneUtils.getVersion(),new String[]{"content","title"},LuceneUtils.getAnalyzer());

TestSearch.java

package com.rk.lucene.g_search;

import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.junit.Test;

import com.rk.lucene.entity.Article;
import com.rk.lucene.utils.LuceneUtils;

public class TestSearch {
	@Test
	public void testAdd() throws Exception{
		List<Article> list = new ArrayList<Article>();
		list.add(new Article(1, "疾风之刃", "《疾风之刃》是一款超动作3D动漫风网游。作为新一代动作游戏,《疾风之刃》呈现出极致华丽的动作表演,精心打磨出的打击感震撼人心。"));
		list.add(new Article(2, "月光疾风", "月光疾风,日本动漫《火影忍者》中的人物,比较个人主义,性格温和。火之国木叶村的特别上忍,中忍考试正赛预选的考官,体质似乎很不好,有着严重的黑眼圈、脸色苍白且经常咳嗽,善用剑术。"));
		list.add(new Article(3, "疾风航班中文版下载", "《疾风航班》是一款优质的动作模拟游戏。游戏中包括亚欧美洲,乃至飞往太空的5条航线,共计50个循序渐进的关卡,以及具有挑战性的Expert级别评定,每个关卡结束后还可进入商店对主角和飞机进..."));
		list.add(new Article(4, "八神疾风", "八神疾风(CV:植田佳奈)是日本动漫《魔法少女奈叶A‘s》首次登场的女角色。暗之书事件中心人物,时空管理局魔导师,擅长贝尔卡式广域·远程魔法。"));
		list.add(new Article(5, "逝去的疾风", "大战中飞得最快的日本飞机,恐怕要数“疾风”战斗机了,它由中岛飞机厂研制生产,制式型号为: 四式单(座)战(斗机),代号キ-84(读作 Ki-84)。"));
		list.add(new Article(6, "疾风剑豪 亚索", "亚索是一个百折不屈的男人,还是一名身手敏捷的剑客,能够运用风的力量来斩杀敌人。这位曾经春风得意的战士因为诬告而身败名裂,并且被迫卷入了一场令人绝望的生存之..."));
		list.add(new Article(7, "疾风知劲草", "疾风知劲草,谓在猛烈的大风中,可看出什么样的草是强劲的。比喻意志坚定,经得起考验。出自《东观汉记·王霸传》:“上谓霸曰:‘颍川从我者皆逝,而子独留,始验疾风知劲草。..."));
		LuceneUtils.addAll(list);
	}

	@Test
	public void testSearch() throws Exception{
		List<Article> list = new ArrayList<Article>();
		String keyword = "疾风";
		//单字段搜索
		//QueryParser queryParser = new QueryParser(LuceneUtils.getVersion(),"content", LuceneUtils.getAnalyzer());
		//多字段搜索,好处:搜索的范围大,最大限度匹配搜索结果
		QueryParser queryParser = 
						new MultiFieldQueryParser(
								LuceneUtils.getVersion(), 
								new String[]{"content","title"}, 
								LuceneUtils.getAnalyzer());
		Query query = queryParser.parse(keyword);

		IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
		TopDocs topDocs = indexSearcher.search(query, 10000);

		for(int i=0;i<topDocs.scoreDocs.length;i++){
			ScoreDoc scoreDoc = topDocs.scoreDocs[i];
			int docIndex = scoreDoc.doc;
			Document document = indexSearcher.doc(docIndex);
			System.out.println("编号为"+document.get("id")+"号的文章得分是" + scoreDoc.score);

			Article article = LuceneUtils.document2javabean(document, Article.class);
			list.add(article);
		}
		indexSearcher.close();
		for(Article article : list){
			System.out.println(article);
		}
	}
}

单列搜索结果

编号为1号的文章得分是0.32994816
编号为7号的文章得分是0.28870463
编号为4号的文章得分是0.23330858
编号为5号的文章得分是0.23330858
编号为2号的文章得分是0.20414501
编号为3号的文章得分是0.20414501

多列搜索结果

编号为1号的文章得分是0.8313483
编号为4号的文章得分是0.76052743
编号为2号的文章得分是0.73915535
编号为7号的文章得分是0.72742975
编号为5号的文章得分是0.68683356
编号为3号的文章得分是0.5180738
编号为6号的文章得分是0.44216305

LuceneUtils.java

package com.rk.lucene.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import com.rk.lucene.entity.Page;

public class LuceneUtils {
	private static Directory directory;
	private static Version version;
	private static Analyzer analyzer;
	private static MaxFieldLength maxFieldLength;
	private static final String LUCENE_DIRECTORY= "D:/rk/indexDB";

	static{
		try {
			directory = FSDirectory.open(new File(LUCENE_DIRECTORY));
			version = Version.LUCENE_30;
			analyzer = new StandardAnalyzer(version);
			maxFieldLength = MaxFieldLength.LIMITED;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	//不让外部new当前帮助类的对象
	private LuceneUtils(){}

	public static <T> void pagination(Page<T> page,String field,String keyword,Class<T> clazz) throws Exception{
		QueryParser queryParser = new QueryParser(getVersion(), field, getAnalyzer()); 
		Query query = queryParser.parse(keyword);

		IndexSearcher indexSearcher = new IndexSearcher(getDirectory());
		TopDocs topDocs = indexSearcher.search(query, 200);
		int totalHits = topDocs.totalHits;
		int curPage = page.getCurPage();
		int pageSize = page.getPageSize();
		int quotient = totalHits / pageSize;
		int remainder = totalHits % pageSize;
		int totalPages = remainder==0 ? quotient : quotient+1;
		int startIndex = (curPage-1) * pageSize;
		int stopIndex = Math.min(startIndex + pageSize, totalHits);
		List<T> list = page.getItems();
		if(list == null){
			list = new ArrayList<T>();
			page.setItems(list);
		}
		list.clear();
		for(int i=startIndex;i<stopIndex;i++){
			ScoreDoc scoreDoc = topDocs.scoreDocs[i];
			int docIndex = scoreDoc.doc;
			Document document = indexSearcher.doc(docIndex);
			T t = document2javabean(document, clazz);
			list.add(t);
		}

		page.setTotalPages(totalPages);
		page.setTotalItems(totalHits);
		indexSearcher.close();
	}

	public static <T> void add(T t) throws Exception{
		Document document = javabean2document(t);
		IndexWriter indexWriter = new IndexWriter(getDirectory(), getAnalyzer(), getMaxFieldLength());
		indexWriter.addDocument(document);
		indexWriter.close();
	}

	public static <T> void addAll(List<T> list) throws Exception{
		IndexWriter indexWriter = new IndexWriter(getDirectory(), getAnalyzer(), getMaxFieldLength());
		for(T t : list){
			Document doc = javabean2document(t);
			indexWriter.addDocument(doc);
		}
		indexWriter.close();
	}

	public static <T> void update(String field,String value,T t) throws Exception{
		Document document = javabean2document(t);
		IndexWriter indexWriter = new IndexWriter(getDirectory(), getAnalyzer(), getMaxFieldLength());
		indexWriter.updateDocument(new Term(field,value), document);
		indexWriter.close();
	}

	public static <T> void delete(String field,String value) throws Exception{
		IndexWriter indexWriter = new IndexWriter(getDirectory(), getAnalyzer(), getMaxFieldLength());
		indexWriter.deleteDocuments(new Term(field,value));
		indexWriter.close();
	}

	/**
	 * 删除所有记录
	 */
	public static void deleteAll() throws Exception {
		IndexWriter indexWriter = new IndexWriter(getDirectory(), getAnalyzer(), getMaxFieldLength());
		indexWriter.deleteAll();
		indexWriter.close();
	}

	/**
	 * 根据关键字进行搜索
	 */
	public static <T> List<T> search(String field,String keyword,int topN,Class<T> clazz) throws Exception{
		List<T> list = new ArrayList<T>();

		QueryParser queryParser = new QueryParser(getVersion(), field, getAnalyzer());
		Query query = queryParser.parse(keyword);

		IndexSearcher indexSearcher = new IndexSearcher(getDirectory());
		TopDocs topDocs = indexSearcher.search(query, topN);

		for(int i=0;i<topDocs.scoreDocs.length;i++){
			ScoreDoc scoreDoc = topDocs.scoreDocs[i];
			int docIndex = scoreDoc.doc;
			System.out.println("文档索引号" + docIndex + ",文档得分:" + scoreDoc.score);
			Document document = indexSearcher.doc(docIndex);
			T entity = (T) document2javabean(document, clazz);
			list.add(entity);
		}
		indexSearcher.close();
		return list;
	}

	/**
	 * 打印List
	 */
	public static <T> void printList(List<T> list){
		if(list != null && list.size()>0){
			for(T t : list){
				System.out.println(t);
			}
		}
	}

	//将JavaBean转成Document对象
	public static Document javabean2document(Object obj) throws Exception{
		//创建Document对象
		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 value = reflectField.get(obj).toString();
			//加入到Document对象中去,这时javabean的属性与document对象的属性相同
			document.add(new Field(name, value, Store.YES, Index.ANALYZED));
		}
		//返回document对象
		return document;
	}

	//将Document对象转换成JavaBean对象
	public static <T> T document2javabean(Document document,Class<T> clazz) throws Exception{
		T obj = clazz.newInstance();
		java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
		for(java.lang.reflect.Field reflectField : reflectFields){
			reflectField.setAccessible(true);
			String name = reflectField.getName();
			String value = document.get(name);
			BeanUtils.setProperty(obj, name, value);
		}
		return obj;
	}

	public static Directory getDirectory() {
		return directory;
	}

	public static void setDirectory(Directory directory) {
		LuceneUtils.directory = directory;
	}

	public static Version getVersion() {
		return version;
	}

	public static void setVersion(Version version) {
		LuceneUtils.version = version;
	}

	public static Analyzer getAnalyzer() {
		return analyzer;
	}

	public static void setAnalyzer(Analyzer analyzer) {
		LuceneUtils.analyzer = analyzer;
	}

	public static MaxFieldLength getMaxFieldLength() {
		return maxFieldLength;
	}

	public static void setMaxFieldLength(MaxFieldLength maxFieldLength) {
		LuceneUtils.maxFieldLength = maxFieldLength;
	}

}
时间: 2024-10-10 01:29:42

Lucene系列:(10)多条件搜索 QueryParser的相关文章

搜索引擎系列 ---lucene简介 创建索引和搜索初步

一.什么是Lucene? Lucene最初是由Doug Cutting开发的,2000年3月,发布第一个版本,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎 :Lucene得名于Doug妻子的中名,同时这也她外祖母的姓;目前是Apache基金会的一个顶级项目,同时也是学习搜索引擎入门必知必会. Lucene 是一个 JAVA 搜索类库,它本身并不是一个完整的解决方案,需要额外的开发工作. 优点:成熟的解决方案,有很多的成功案例.apache 顶级项目,正在持续快速的进步.庞大而活跃的开

搜索引擎系列 -lucene简介 创建索引和搜索初步步骤

一.什么是Lucene? Lucene最初是由Doug Cutting开发的,2000年3月,发布第一个版本,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎 :Lucene得名于Doug妻子的中名,同时这也她外祖母的姓;目前是Apache基金会的一个顶级项目,同时也是学习搜索引擎入门必知必会. Lucene 是一个 JAVA 搜索类库,它本身并不是一个完整的解决方案,需要额外的开发工作. 优点:成熟的解决方案,有很多的成功案例.apache 顶级项目,正在持续快速的进步.庞大而活跃的开

整合Lucene 4.10.1 与IK Analyzer

注意,IK Analyzer需要使用其下载列表中的 IK Analyzer 2012FF_hf1.zip,否则在和Lucene 4.10配合使用时会报错. 我使用 intellij IDEA 12进行的测试. 建立java项目 建立项目HelloLucene,导入Lucene的几个库."File"->"Project Structure"-> 将IK Analyzer 2012FF_hf1.zip解压后的源码放入src目录,并将字典和配置文件放入src目

使用Lucene.NET实现站内搜索

使用Lucene.NET实现站内搜索 导入Lucene.NET 开发包 Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎.Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎.Lucene.Net 是 .NET 版的Lucene. 你可以在这里下载到最新的Lucene.NET 创建索引.更新索引.删除索引 搜索

社保系列10——返回值速查表

9000 命令执行成功 6006 依据传输模式,所要读取的字节长度错 61xx 正常处理.'xx'表示可以通过后续 GET RESPONSE命令得到的额外数据长度 6281 回送数据可能出错 6282 文件长度<Le 6283 选择文件无效 6284 FCI格式与P2指定的不符 6300 认证失败 63Cx 验证失败,x =0 表示不提供计数器 x !=0 表示重试次数 6581 EEPROM损坏,导致卡锁定 6700 Lc或Le长度错 6900 无信息提供 6901 命令不接受(无效状态) 6

AJAX实现导航式多条件搜索

导航式搜索在实际网站开发中有很多应用,其实现原理也不复杂,关键是如何记忆所选的条件.常见的方式有存入session.存入数组等.本文采用的是AJAX+数组的方式,在不跳转,不刷新整个页面的条件下动态返回查询结果. 效果图如下: 1.search.jsp 通过将所选的查询条件存入数组,通过AJAX传到后台,这样在后台利用所得到的查询条件,就可以到数据库进行查询了.代码如下: <%@ page language="java"  import="java.util.List;

列表页的动态条件搜索

在我是如何做列表页的,我提到了列表页的动态条件搜索,主要的目的就是在View中能够动态的指定条件,而后端的数据查询逻辑尽量不变.之前在搞.net的时候,我们可以借助强大的ExpressionTree来解决,之前有一篇是微软的EntityFramework表达式转换:Linq to Entity经验:表达式转换,是将一种表达式转换成数据库组件能够识别的表达式,只不过那篇没有涉及到View中的条件而已.页面动态查询的最简单的方法就是解析View中特定的值来得到后台组件能够识别的查询逻辑.    我们

8.Swift教程翻译系列——控制流之条件

3.条件语句 经常会需要根据不同的情况来执行不同的代码.你可能想要在发生错误的时候执行一段额外的代码,或者当某个值变得太高或者太低的时候给他输出出来.要实现这些需求,你可以使用条件分支. Swift提供两种方式来实现条件分支,也就是if语句和switch语句.一般来说If用在可能的情况比较少的简单条件中,当遇到复杂条件有很多种可能性的时候使用switch会更好,或者要根据模式匹配来判断要执行什么代码的时候switch也很有用. if语句 if的最简单形式只有一个单独的if条件,只有当条件为tru

EMVTag系列10——发卡行公钥证书

?  90  发卡行公钥(IPK)证书 L: NCA -C(有条件):如果支持SDA,DDA CA认证过的发卡行公钥.用于脱机数据认证 ?  9F32    发卡行公钥指数 L: 1 or 3 -C(有条件):如果支持SDA,DDA 发卡行公钥指数,用来验证签名的静态应用数据和IC卡公钥证书 ?  92  发卡行公钥余项 L: NI-NCA+36 -C(有条件):如果需要 没有放入发卡行公钥证书中的发卡行公钥部分 ?  8F  认证中心公钥索引 F: b 8 T: 8F L: 1 -C(有条件)