lucene自定义排序
lucene自定义排序
天地有雪 发表于3年前
lucene自定义排序
  • 发表于 3年前
  • 阅读 67
  • 收藏 1
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

摘要: 使用lucene提供的FieldComparatorSource和FieldComparator自定义排序

lucene本身提供很多默认的排序方式,比如根据相关度,写入索引的顺序,域的值等等,提供正向或者逆向的排序,大部分情况下,这已经能满足我们的基本要求。但在实际的应用中,也有一些需求,需要搜索的结果,依据搜索内容进行排序,比如在搜跟当前位置相关的对象时,需要根据距离的远近,来对返回的结果进行排序。每一次搜索的坐标不一样,因此,在搜索的过程中,需要动态来计算匹配对象和搜索坐标的距离。lucene提供了自定义的排序的功能。需要继承FieldComparatorSource和FieldComparator这两个抽象类。

本文中所举的例子也比较常见,使用WildcardQuery进行通配符匹配搜索,在搜索多个对象的名称时,默认返回结果是依据写入索引的id由小到大返回的(打分都是1.0)。在匹配结果太多的时候,用户体检非常糟糕。当然,可以进行分词,然后计算得分的高低返回。这里换一个思路,依旧使用WildcardQuery进行通配符匹配搜索,但对搜索的结果,依据搜索字符串和匹配对象名称的字符串计算编辑距离,然后排序。实际上,这就是sql like功能的lucene实现。

StrDistanceComparatorSouce 是我们定义的类,继承FieldComparatorSource,保存了每一次搜索query的name,然后使用FieldComparator的继承类来实现搜索结果的排序。

StrFieldComparator是FieldComparator的继承类,同时,也是StrDistanceComparatorSouce 的内部类,这样就可以方便使用StrDistanceComparatorSouce 中的name,继承FieldComparator需要实现5个方法,具体功能查lucene文档,代码如下。

public class StrDistanceComparatorSource extends FieldComparatorSource {
	private static final Logger logger = Logger
			.getLogger(StrDistanceComparatorSource.class);
	private static final long serialVersionUID = 1L;
	private String name;

	public StrDistanceComparatorSource(String name) {
		this.name = name;
	}

	@Override
	public FieldComparator<?> newComparator(String fieldName, int numHits,
			int sortPost, boolean reversed) throws IOException {
		return new StrFieldComparator(fieldName, numHits);
	}

@SuppressWarnings("rawtypes")
	private class StrFieldComparator extends FieldComparator {

		private String[] nameDoc;
		private int[] values;

		private int bottom;

		private final String field;

		public StrFieldComparator(String field, int numHits) throws IOException {
			values = new int[numHits];
			this.field = field;
		}

		@Override
		public int compare(int slot1, int slot2) {
			if (values[slot1] > values[slot2])
				return 1;
			if (values[slot1] < values[slot2])
				return -1;
			return 0;
		}

		private int getDistance(int doc) {
			if (name == null) {
				logger.error("name is null");
				name = "";
			}
			if (nameDoc[doc] == null) {
				logger.error("name doc is null");
				nameDoc[doc] = "";
			}
			return StringUtils.getLevenshteinDistance(name, nameDoc[doc]);
		}

		@Override
		public int compareBottom(int doc) throws IOException {
			int distance = getDistance(doc);
			if (bottom < distance)
				return -1;
			if (bottom > distance)
				return 1;
			return 0;
		}

		@Override
		public void copy(int slot, int doc) throws IOException {
			values[slot] = getDistance(doc);

		}

		@Override
		public void setBottom(int slot) {
			bottom = values[slot];
		}

		@Override
		public void setNextReader(IndexReader reader, int docBase)
				throws IOException {
			nameDoc = FieldCache.DEFAULT.getStrings(reader, this.field);
		}

		@Override
		public Comparable value(int slot) {
			return this.values[slot];
		}

最后生成自定义的排序器,首先按照编辑距离排序,如果编辑距离相同,则按照索引的id从低到高进行排序。

Sort sort = new Sort(new SortField("name",
					new StrDistanceComparatorSource(queryStr)),
					SortField.FIELD_DOC);


  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 1
博文 12
码字总数 9088
×
天地有雪
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: