Lucene3.5自定义评分以及根据域进行自定义评分设定

一、首先来综述一下Lucene自定义评分的步骤:

1、创建一个评分域

FieldScoreQuery fd = new FieldScoreQuery("score", Type.INT);

2、根据评分域和原有的query创建自定义的query对象

MyCustomScoreQuery query = new MyCustomScoreQuery(q, fd);
@SuppressWarnings("serial")
	private class MyCustomScoreQuery extends CustomScoreQuery {

		public MyCustomScoreQuery(Query subQuery, ValueSourceQuery valSrcQuery) {
			super(subQuery, valSrcQuery);

		}

		@Override
		protected CustomScoreProvider getCustomScoreProvider(IndexReader reader)
				throws IOException {
			//默认情况实现的评分是通过原有的评分*传入进来的评分域所获取的评分来确定最终评分的
			//为了根据不同的需求进行评分,需要自己进行评分的设定
			/**
			 * 自定评分的步骤
			 * 创建一个类继承于CustomScoreProvider
			 * 覆盖customScore方法
			 */
			//return super.getCustomScoreProvider(reader);
			return new MyCustomScoreProvider(reader);
		}
	}



3、创建一个类继承于CustomScoreProvider,覆盖customScore方法

private class MyCustomScoreProvider extends CustomScoreProvider {

		public MyCustomScoreProvider(IndexReader reader) {
			super(reader);
		}
        /**
         * subQueryScore表示默认文档的打分
         * valSrcScore表示评分域的打分
         */
		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			//return super.customScore(doc, subQueryScore, valSrcScore);
			return subQueryScore/valSrcScore;
		}

	}

二、根据域进行自定义评分设定

1、根据文件后缀名进行自定义评分

private class FilenameScoreQuery extends CustomScoreQuery {

		public FilenameScoreQuery(Query subQuery) {
			super(subQuery);
		}

		@Override
		protected CustomScoreProvider getCustomScoreProvider(IndexReader reader)
				throws IOException {
			//return super.getCustomScoreProvider(reader);
			return new FilenameScoreProvider(reader);
		}
	}

	private class FilenameScoreProvider extends CustomScoreProvider {
		String [] filenames = null;
		public FilenameScoreProvider(IndexReader reader) {
			super(reader);
			try {
				filenames = FieldCache.DEFAULT.getStrings(reader, "filename");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			//如何根据doc获取相应的field的值
			/**
			 * 在reader没有关闭之前,所有的数据会存储在一个缓存域中,可以通过缓存获取很多有用的信息
			 * filenames = FieldCache.DEFAULT.getStrings(reader, "filename");可以获取所有的filename域的信息
			 */
			String filename = filenames[doc];
			if(filename.endsWith(".txt")||filename.endsWith(".ini")) {
				return subQueryScore*1.5f;
			}
			//return super.customScore(doc, subQueryScore, valSrcScore);
			return subQueryScore/1.5f;
		}
	}

2、根据日期进行自定义评分

private class DateScoreProvider extends CustomScoreProvider {
		long[] dates = null;
		public DateScoreProvider(IndexReader reader) {
			super(reader);
			try {
				dates = FieldCache.DEFAULT.getLongs(reader, "date");
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			long date = dates[doc];
			long today = new Date().getTime();
			long year = 1000*60*60*365;
			if(today - date <= year) {
				//为其加分
			}

			return super.customScore(doc, subQueryScore, valSrcScore);
		}

	}

Lucene实现自定义评分的关键思想:

indexSearch.search中要传入一个CustomScoreQuery,要覆盖getCustomScoreProvider方法,并且要返回CustomScoreProvider
对象,在用匿名内部内的方式写一个CustomScoreProvider 覆盖customScore方法,这个方法有3个参数,第一个参数代表文档id,第二个参数代表原来评分,最后一个代表我们设置的评分域,然后我们就可以定义自己的一套评分算法为我们的搜索制定评分了。

完整代码如下:

1、工具类:

package com.dhb.util;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Random;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;

public class FileIndexUtils {
	private static Directory directory = null;
	static {
		try {
			directory = FSDirectory.open(new File("D:/luceneData/files/"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static Directory getDirectory() {
		return directory;
	}
	public static void index(boolean hasNew) {
		IndexWriter writer = null;
		try {
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_35,
					new StandardAnalyzer(Version.LUCENE_35));
			writer = new IndexWriter(directory, iwc);
			//是否新建索引
			if(hasNew) {
				writer.deleteAll();
			}
			Document doc = null;
			File f = new File("D:/luceneData/example");

			Random rand = new Random();

			int index = 0;

			for (File file : f.listFiles()) {
				int score = rand.nextInt(600);  //测试自定义评分用的

				doc = new Document();
				//测试自定义Filter用的
				doc.add(new Field("id", String.valueOf(index++), Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));

				doc.add(new Field("content", new FileReader(file)));
				doc.add(new Field("filename", file.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
				doc.add(new Field("path",file.getAbsolutePath(),Field.Store.YES,Field.Index.NOT_ANALYZED));
				doc.add(new NumericField("date", Field.Store.YES, true).setLongValue(file.lastModified()));
				doc.add(new NumericField("size", Field.Store.YES, true).setIntValue((int) (file.length())));

				doc.add(new NumericField("score", Field.Store.YES, true).setIntValue(score));
				writer.addDocument(doc);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(writer!=null)
				try {
					writer.close();
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}
}

注意:(先自己生成索引,我这里就没调用了,因为放在另一个地方了,没有贴了)

2、自定义类

package com.dhb.util;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.function.CustomScoreProvider;
import org.apache.lucene.search.function.CustomScoreQuery;
import org.apache.lucene.search.function.FieldScoreQuery;
import org.apache.lucene.search.function.FieldScoreQuery.Type;
import org.apache.lucene.search.function.ValueSourceQuery;

public class MyScoreQuery {
	public void searchByScoreQuery() {
		try {
			IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtils.getDirectory()));
		    Query q = new TermQuery(new Term("content", "java"));
		    //1、创建一个评分域
		    FieldScoreQuery fd = new FieldScoreQuery("score", Type.INT);
		    //2、根据评分域和原有的query创建自定义的query对象
		    MyCustomScoreQuery query = new MyCustomScoreQuery(q, fd);

		    TopDocs tds = null;
		    tds = searcher.search(query, 100);

		    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			for (ScoreDoc sd : tds.scoreDocs) {
				Document d = searcher.doc(sd.doc);
				System.out.println(sd.doc + ":(" + sd.score + ")["
						+ d.get("filename") + "【" + d.get("path") + "】---"
						+ d.get("size") + "----" + sdf.format(Long.valueOf(d.get("date")))+"自定义评分:"+d.get("score"));
			}

		    searcher.close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void searchByFileScoreQuery() {
		try {
			IndexSearcher searcher = new IndexSearcher(IndexReader.open(FileIndexUtils.getDirectory()));
		    Query q = new TermQuery(new Term("content", "java"));
		    //1、创建一个评分域
		    //FieldScoreQuery fd = new FieldScoreQuery("score", Type.INT);
		    FilenameScoreQuery query = new FilenameScoreQuery(q);

		    //2、根据评分域和原有的query创建自定义的query对象
		    //MyCustomScoreQuery query = new MyCustomScoreQuery(q, fd);

		    TopDocs tds = null;
		    tds = searcher.search(query, 100);

		    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			for (ScoreDoc sd : tds.scoreDocs) {
				Document d = searcher.doc(sd.doc);
				System.out.println(sd.doc + ":(" + sd.score + ")["
						+ d.get("filename") + "【" + d.get("path") + "】---"
						+ d.get("size") + "----" + sdf.format(Long.valueOf(d.get("date")))+"自定义评分:"+d.get("score"));
			}

		    searcher.close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("serial")
	private class MyCustomScoreQuery extends CustomScoreQuery {

		public MyCustomScoreQuery(Query subQuery, ValueSourceQuery valSrcQuery) {
			super(subQuery, valSrcQuery);

		}

		@Override
		protected CustomScoreProvider getCustomScoreProvider(IndexReader reader)
				throws IOException {
			//默认情况实现的评分是通过原有的评分*传入进来的评分域所获取的评分来确定最终评分的
			//为了根据不同的需求进行评分,需要自己进行评分的设定
			/**
			 * 自定评分的步骤
			 * 创建一个类继承于CustomScoreProvider
			 * 覆盖customScore方法
			 */
			//return super.getCustomScoreProvider(reader);
			return new MyCustomScoreProvider(reader);
		}
	}

	private class MyCustomScoreProvider extends CustomScoreProvider {

		public MyCustomScoreProvider(IndexReader reader) {
			super(reader);
		}
        /**
         * subQueryScore表示默认文档的打分
         * valSrcScore表示评分域的打分
         */
		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			//return super.customScore(doc, subQueryScore, valSrcScore);
			return subQueryScore/valSrcScore;
		}

	}

	@SuppressWarnings("serial")
	private class FilenameScoreQuery extends CustomScoreQuery {

		public FilenameScoreQuery(Query subQuery) {
			super(subQuery);
		}

		@Override
		protected CustomScoreProvider getCustomScoreProvider(IndexReader reader)
				throws IOException {
			//return super.getCustomScoreProvider(reader);
			return new FilenameScoreProvider(reader);
		}
	}

	private class FilenameScoreProvider extends CustomScoreProvider {
		String [] filenames = null;
		public FilenameScoreProvider(IndexReader reader) {
			super(reader);
			try {
				filenames = FieldCache.DEFAULT.getStrings(reader, "filename");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			//如何根据doc获取相应的field的值
			/**
			 * 在reader没有关闭之前,所有的数据会存储在一个缓存域中,可以通过缓存获取很多有用的信息
			 * filenames = FieldCache.DEFAULT.getStrings(reader, "filename");可以获取所有的filename域的信息
			 */
			String filename = filenames[doc];
			if(filename.endsWith(".txt")||filename.endsWith(".ini")) {
				return subQueryScore*1.5f;
			}
			//return super.customScore(doc, subQueryScore, valSrcScore);
			return subQueryScore/1.5f;
		}
	}
	@SuppressWarnings("unused")
	private class DateScoreProvider extends CustomScoreProvider {
		long[] dates = null;
		public DateScoreProvider(IndexReader reader) {
			super(reader);
			try {
				dates = FieldCache.DEFAULT.getLongs(reader, "date");
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		@Override
		public float customScore(int doc, float subQueryScore, float valSrcScore)
				throws IOException {
			long date = dates[doc];
			long today = new Date().getTime();
			long year = 1000*60*60*365;
			if(today - date <= year) {
				//为其加分
			}

			return super.customScore(doc, subQueryScore, valSrcScore);
		}

	}
}

3、测试类

package com.dhb.test;

import org.junit.Test;

import com.dhb.util.MyScoreQuery;

public class TestCustomScore {
	@Test
	public void test01() {
		MyScoreQuery msq = new MyScoreQuery();
		msq.searchByScoreQuery();
	}
	@Test
	public void test02() {
		MyScoreQuery msq = new MyScoreQuery();
		msq.searchByFileScoreQuery();
	}
}
时间: 2024-10-09 14:49:06

Lucene3.5自定义评分以及根据域进行自定义评分设定的相关文章

Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]

1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发送请求url的协议.域名.端口三者之间任意一与当前页面地址不同即为跨域. 具体可以查看下表: 2.springboot如何解决跨域问题 1.普通跨域请求解决方案: ①请求接口添加注解@CrossOrigin(origins = "http://127.0.0.1:8020", maxAge

Servlet学习笔记(八)—— 自定义过滤器的编写改进:自定义实现FilterChain

笔记六中实现了三种过滤器:字符编码过滤.登录权限过滤.敏感词过滤,但是有个缺陷就是,限定了过滤顺序,而不能实现先进行request过滤,最后response过滤,并且中间几项过滤的顺序不能动态改变.所以这里做个改进,实现一个过滤顺序的FilterChain. 多个Filter的执行顺序在这篇博文中得到很仔细的讲解,总结一点,多个过滤器的执行顺序是根据web.xml中不同<filter-mapping>的顺序来先后执行的,比如: <?xml version="1.0"

Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件(转)

一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: 1.对Android中Window类中的DecorView有所了解 2.对Scroller类实现平滑移动效果 3.自定义ViewGroup的实现 首先来看看效果图吧:    下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XC

css简单实现五角星评分、点赞收藏、展示评分(半颗星、1/3颗星)

1.前言 之前做的好几个项目中,都会遇到打分,评分,点赞这样的需求,写了很多次,每次需要再写的时候,就会翻出之前写过的代码,然后copy过来.总觉得这样的话没有进步,没有把知识放进脑袋里,所以,自己花了2个小时,把这三种类型的需求自己写了demo并做了演示,这样的话,感觉一字一字敲出来的代码,确实是到了脑袋里了.之前一直崇尚写简单的博客,也将五角星评分.点赞收藏.展示评分写成了三个简单的博客,奈何博客园要求博客要有篇幅,所以我的那三篇博客并没有上到博客园首页,但是我觉得这个方法应该让更多的小伙伴

自定义View基础 - 最易懂的自定义View原理系列(1)

前言 自定义View原理是Android开发者必须了解的基础: 在了解自定义View之前,你需要有一定的知识储备: 本文将全面解析关于自定义View中的所有知识基础. 目录 1. View的分类 视图View主要分为两类: 类别 解释 特点 单一视图 即一个View,如TextView 不包含子View 视图组 即多个View组成的ViewGroup,如LinearLayout 包含子View 2. View类简介 View类是Android中各种组件的基类,如View是ViewGroup基类

漫谈js自定义事件、DOM/伪DOM自定义事件

一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木有?则RSS或盗版)然后撤了. 事件是个大课题,真要从断奶开始讲起的话,可以写个12期的连载.关于JS事件的文章(类似DOM/BOM事件模型,IE与其他浏览器事件差异,DOM1/DOM2事件定义等)落叶般随处可见.熟豆子反复炒一点意思都没有,因此,这里谈谈自己感兴趣的自定义事件以及周边. 所谓自定义

java自定义Annotation,得到注解类中Annotation设定的注解值

java注解机制在各大框架中应用普遍,注解中可以设置一些值,如何得到呢. 要得到注解类中Annotation设定的注解值 即:遍历自定义Annotation中的方法,反射执行方法,结果就是 对应的注解值. java代码例子: package com.doctor.spring.core; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotat

js自定义事件、DOM/伪DOM自定义事件

一.说明.引言 我JS还是比较薄弱的,本文的内容属于边学边想边折腾的碎碎念,可能没什么条理,可能有表述不准确的地方,可能内容比较拗口生僻.如果您时间紧迫,或者JS造诣已深,至此您就可以点击右侧广告(木有?则RSS或盗版)然后撤了. 事件是个大课题,真要从断奶开始讲起的话,可以写个12期的连载.关于JS事件的文章(类似DOM/BOM事件模型,IE与其他浏览器事件差异,DOM1/DOM2事件定义等)落叶般随处可见.熟豆子反复炒一点意思都没有,因此,这里谈谈自己感兴趣的自定义事件以及周边. 所谓自定义

java_自定义标签,我的第一个自定义标签!

自定义标签,我的第一个自定义标签! 总共分两步 编写一个实现tag接口的java类,把jsp页面中的java代码移到这个类中,(标签处理器类) 编写标签库描述符(tld)文件,在tld文件中把标签处理器类描述成一个标签 一.案例, 输出客户端IP ViewIP.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&g