Lucene 时间排序
在Lucene4.4中,想要实现搜索结果按照时间倒序的效果:如果两个文档得分相同,那么就按照发布时间倒序排列;否则就按照分数排列。这种效果在Lucene4.6中实现起来极其简单,直接利用search接口的Sort参数即可达成,完全不需要像某些人说的重写Similarity那么麻烦。三两行代码的事情,体现了Make it simple, stupid的精髓。
首先来看看测试例子,这个例子中我建立了四个文档,按照内容-发布日期来表示分别是:
2004年光棍节攻略 , 20041111
2005年光棍节攻略 , 20051111
2006年光棍节攻略 , 20061111
游戏攻略 ,20141111
统一使用“光棍节攻略”来搜索它们,用户希望最新的光棍节攻略排在第一。
如果不做排序处理的话,用户体验非常糟糕:
- package com.hankcs.test;
- import org.apache.lucene.analysis.Analyzer;
- import org.apache.lucene.document.*;
- import org.apache.lucene.index.*;
- import org.apache.lucene.queries.CustomScoreQuery;
- import org.apache.lucene.queries.function.FunctionQuery;
- import org.apache.lucene.queryparser.classic.ParseException;
- import org.apache.lucene.queryparser.classic.QueryParser;
- import org.apache.lucene.search.*;
- import org.apache.lucene.store.Directory;
- import org.apache.lucene.store.LockObtainFailedException;
- import org.apache.lucene.store.RAMDirectory;
- import org.apache.lucene.util.Version;
- import org.wltea.analyzer.lucene.IKAnalyzer;
- import java.io.IOException;
- /**
- * @author hankcs
- */
- public class TestSortByTime
- {
- public static void main(String[] args)
- {
- // Lucene Document的主要域名
- String fieldName = "text";
- // 实例化IKAnalyzer分词器
- Analyzer analyzer = new IKAnalyzer();
- Directory directory = null;
- IndexWriter iwriter;
- IndexReader ireader = null;
- IndexSearcher isearcher;
- try
- {
- //索引过程**********************************
- //建立内存索引对象
- directory = new RAMDirectory();
- //配置IndexWriterConfig
- IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_46, analyzer);
- iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
- iwriter = new IndexWriter(directory, iwConfig);
- //写入索引
- for (int i = 0; i < 3; ++i)
- {
- int year = 2004 + i;
- Document doc = new Document();
- doc.add(new TextField(fieldName, year + "年光棍节攻略", Field.Store.YES));
- doc.add(new IntField("date", year * 10000 + 1111, Field.Store.YES));
- iwriter.addDocument(doc);
- }
- // 加入一个干扰文档
- Document doc = new Document();
- doc.add(new TextField(fieldName, "游戏攻略", Field.Store.YES));
- doc.add(new IntField("date", 20141111, Field.Store.YES));
- iwriter.addDocument(doc);
- iwriter.close();
- //搜索过程**********************************
- //实例化搜索器
- ireader = DirectoryReader.open(directory);
- isearcher = new IndexSearcher(ireader);
- String keyword = "光棍节攻略";
- //使用QueryParser查询分析器构造Query对象
- QueryParser qp = new QueryParser(Version.LUCENE_46, fieldName, analyzer);
- Query query = qp.parse(keyword);
- System.out.println("Query = " + query);
- //搜索相似度最高的5条记录
- TopDocs topDocs = isearcher.search(query, 5);
- System.out.println("命中:" + topDocs.totalHits);
- //输出结果
- ScoreDoc[] scoreDocs = topDocs.scoreDocs;
- for (int i = 0; i < Math.min(5, scoreDocs.length); i++)
- {
- Document targetDoc = isearcher.doc(scoreDocs[i].doc);
- System.out.print(targetDoc.getField(fieldName).stringValue());
- System.out.print(" , " + targetDoc.getField("date").numericValue());
- System.out.println(" , " + scoreDocs[i].score);
- }
- } catch (CorruptIndexException e)
- {
- e.printStackTrace();
- } catch (LockObtainFailedException e)
- {
- e.printStackTrace();
- } catch (IOException e)
- {
- e.printStackTrace();
- } catch (ParseException e)
- {
- e.printStackTrace();
- } finally
- {
- if (ireader != null)
- {
- try
- {
- ireader.close();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- if (directory != null)
- {
- try
- {
- directory.close();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- }
- }
- }
输出:
2004年光棍节攻略 , 20041111 , 0.71185887
2005年光棍节攻略 , 20051111 , 0.71185887
2006年光棍节攻略 , 20061111 , 0.71185887
游戏攻略 , 20141111 , 0.049675122
可以看到文档是严格按照分数排序的,如果分数相同,则按照索引顺序排序,导致最新的文章反而排在最下面。
使用search接口的Sort参数优化搜索结果:
- package com.hankcs.test;
- import org.apache.lucene.analysis.Analyzer;
- import org.apache.lucene.document.*;
- import org.apache.lucene.index.*;
- import org.apache.lucene.queries.CustomScoreQuery;
- import org.apache.lucene.queries.function.FunctionQuery;
- import org.apache.lucene.queryparser.classic.ParseException;
- import org.apache.lucene.queryparser.classic.QueryParser;
- import org.apache.lucene.search.*;
- import org.apache.lucene.store.Directory;
- import org.apache.lucene.store.LockObtainFailedException;
- import org.apache.lucene.store.RAMDirectory;
- import org.apache.lucene.util.Version;
- import org.wltea.analyzer.lucene.IKAnalyzer;
- import java.io.IOException;
- /**
- * @author hankcs
- */
- public class TestSortByTime
- {
- public static void main(String[] args)
- {
- // Lucene Document的主要域名
- String fieldName = "text";
- // 实例化IKAnalyzer分词器
- Analyzer analyzer = new IKAnalyzer();
- Directory directory = null;
- IndexWriter iwriter;
- IndexReader ireader = null;
- IndexSearcher isearcher;
- try
- {
- //索引过程**********************************
- //建立内存索引对象
- directory = new RAMDirectory();
- //配置IndexWriterConfig
- IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_46, analyzer);
- iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
- iwriter = new IndexWriter(directory, iwConfig);
- //写入索引
- for (int i = 0; i < 3; ++i)
- {
- int year = 2004 + i;
- Document doc = new Document();
- doc.add(new TextField(fieldName, year + "年光棍节攻略", Field.Store.YES));
- doc.add(new IntField("date", year * 10000 + 1111, Field.Store.YES));
- iwriter.addDocument(doc);
- }
- // 加入一个干扰文档
- Document doc = new Document();
- doc.add(new TextField(fieldName, "游戏攻略", Field.Store.YES));
- doc.add(new IntField("date", 20141111, Field.Store.YES));
- iwriter.addDocument(doc);
- iwriter.close();
- //搜索过程**********************************
- //实例化搜索器
- ireader = DirectoryReader.open(directory);
- isearcher = new IndexSearcher(ireader);
- String keyword = "光棍节攻略";
- //使用QueryParser查询分析器构造Query对象
- QueryParser qp = new QueryParser(Version.LUCENE_46, fieldName, analyzer);
- Query query = qp.parse(keyword);
- System.out.println("Query = " + query);
- //搜索相似度最高的5条记录
- Sort sort = new Sort(new SortField("text", SortField.Type.SCORE), new SortField("date", SortField.Type.INT, true));
- TopDocs topDocs = isearcher.search(query, 5, sort);
- System.out.println("命中:" + topDocs.totalHits);
- //输出结果
- ScoreDoc[] scoreDocs = topDocs.scoreDocs;
- for (int i = 0; i < Math.min(5, scoreDocs.length); i++)
- {
- Document targetDoc = isearcher.doc(scoreDocs[i].doc);
- System.out.print(targetDoc.getField(fieldName).stringValue());
- System.out.print(" , " + targetDoc.getField("date").numericValue());
- System.out.println(" , " + scoreDocs[i].score);
- }
- } catch (CorruptIndexException e)
- {
- e.printStackTrace();
- } catch (LockObtainFailedException e)
- {
- e.printStackTrace();
- } catch (IOException e)
- {
- e.printStackTrace();
- } catch (ParseException e)
- {
- e.printStackTrace();
- } finally
- {
- if (ireader != null)
- {
- try
- {
- ireader.close();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- if (directory != null)
- {
- try
- {
- directory.close();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- }
- }
- }
输出结果:
命中:4
2006年光棍节攻略 , 20061111 , NaN
2005年光棍节攻略 , 20051111 , NaN
2004年光棍节攻略 , 20041111 , NaN
游戏攻略 , 20141111 , NaN
我们看到“2006年光棍节攻略”因为时间比较新,并且相关性高,就排在了第一。“2005年光棍节攻略”相关度相同,因为时间旧就排在后面一点,而干扰文档“游戏攻略”即使时间最新,因为不相关的原因排在最后面。这种效果正好是我想要的,极大提升了用户体验。
Lucene 时间排序的更多相关文章
- lucene之排序、设置权重、优化、分布式搜索(转)
lucene之排序.设置权重.优化.分布式搜索(转) 1. 基本应用 using System;using System.Collections.Generic;using System.Text;u ...
- 如何对sharepoint图片库的文件夹的图片按照时间排序并分页显示
/// <summary> /// 获取图片库第一层文件夹--根据文件夹名称排序 /// </summary> /// <param name="siteUrl ...
- ls按时间排序输出文件列表
文件转自:http://www.2cto.com/os/201303/197829.html ls按时间排序输出文件列表 首先,ls --help查看ls相关的与时间排序相关的参数: > ...
- C#实现对指定文件夹中文件按修改时间排序
string path = "~/Document/Introduction/团队管理制度/"; DirectoryInfo dirinfo = new Di ...
- PHP读取文件夹目录,按时间排序,大小排序,名字排序
工作中有时候会遇到文件存储数据,但是在前台显示的时候又因为没有数据库,无法使用上传或最后一次修改日期字段排序,所以有了如下代码: <?php $dir = "./";//目录 ...
- lucene查询排序结果原理总结
参考文章 Lucene3.0结果排序原理+操作+示例 Lucene的排序算法 一句话总结lucene排序算法是什么样的 关键几个概念 参考文档: http://lucene.apache.org/co ...
- 几种能在O(n*log(n))时间排序
线性时间排序 各种排序算法总结已经介绍了几种能在O(n*log(n))时间内培训n个数的算法.归并排序和堆排序达到了最坏情况下的上界:快速排序在平均情况下达到该上界.这些算法都有一个有趣的性质:在 ...
- linux_常用命令_(ls, lsof,nslookup)_查看文件按照时间排序
平时收集些用到的命令 方便使用 1: ls -lrt 按时间排序 展示 2:nslookup 查看dns解析 3:lsof -p 进程号 lsof `which httpd` //那个进程在使用 ...
- Linux中ls对文件进行按大小排序和按时间排序,设置ls时间格式
1 按文件大小排序 使用 ll -S | grep '^[^d]' // 格式化文件大小形式 ll -Sh | grep '^[^d]' 2 按文件修改时间排序显示 使用 ll -rt 3 设置ls ...
随机推荐
- 自定义从Azure下载回来的远程桌面连接(.rdp)文件,使其提供更多丰富功能
通常情况下,我们使用Azure的时候微软会为用户提供可连接管理虚拟机的远程桌面服务,并且支持文件实例的保存,对于Windows 系统来说,微软提供的链接文件实例就是.rdp文件. 获得.rdp文件 打 ...
- 1Z0-053 争议题目解析512
1Z0-053 争议题目解析512 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 512.Which two statements correctly describe the r ...
- Cesium原理篇:6 Renderer模块(2: Texture)
Texture也是WebGL中重要的概念,使用起来也很简单.但有句话叫大道至简,如果真的想要用好纹理,里面的水其实也是很深的.下面我们来一探究竟. 下面是WebGL中创建一个纹理的最简过程: var ...
- 解析ActionResult子类JsonResult
前言 MVC我是11开始使用的,当时还是在上地软件园一小型互联网公司,当时是MVC2.0+Linq to sql.后来接着学习MVC3,MVC3的出现确实让我有种眼前一亮的感觉,期间我不断的写各种de ...
- javascript判断元素存在和判断元素存在于实时的dom中的方法
今天(周六)下午我在公司加班时不知道要干什么,就打开公司的一个wordpress项目网站,想看下之前自己做的一个网页是否有问题. 打开网站首页,我习惯性的打开了chrome的调试工具,然后鼠标开始滚动 ...
- Unity打开摄像头占满全屏
Unity打开摄像头占满全屏 AR项目需求,Unity打开摄像头作为背景渲染占满全屏~ Unity对设备硬件操作的API并不是太友好~打开一个摄像头,渲染到屏幕上也都得自己写,虽然步骤少,提取摄像头t ...
- 让动态的 iframe 内容高度自适应
使用iframe加载其他页面的时候,需要自适应iframe的高度 这里加载了两个不同内容高度的页面至iframe中 1. 没有设置高度 <div class="iframe-wrapp ...
- Jquery.Qrcode在客户端动态生成二维码并添加自定义Logo
0 Jquery.Qrcode简介 Jquery.Qrcode.js是一个在浏览器端基于Jquery动态生成二维码的插件,支持Canvas和Table两种渲染方式,它的优点是在客户端动态生成,减轻了服 ...
- 关系数据库SQL之基本数据查询:子查询、分组查询、模糊查询
前言 上一篇关系数据库常用SQL语句语法大全主要是关系型数据库大体结构,本文细说一下关系型数据库查询的SQL语法. 语法回顾 SELECT [ALL|DISTINCT] <目标列表达式>[ ...
- Web页面实现后台数据处理进度与剩余时间的显示
1.页面后台代码添加如下属性: /// <summary> /// 总数 /// </summary> private double total { set { Session ...