`
wu_quanyin
  • 浏览: 208256 次
  • 性别: Icon_minigender_1
  • 来自: 福建省
社区版块
存档分类
最新评论

Lucene---全文检索(处理一对多去重问题 )

阅读更多

在处理如"问答"功能时,以答进行搜索,这时假就会出现去重问题--->http://www.iteye.com/problems/56869

 

 

解决方案:

1,写个线程管理器,用来存储当前查出的重复数据

 

/*
 * CopyRright (c)  www.fdauto.com
 */
package com.fdauto.bws.business.module.lucene.duplicate;

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

/**
 * 
 *用于管理在一个线程内共用一个Map
 * 
 * @author 09817(wu_quanyin)
 * @date 2011-01-06 上午17:02:44
 * @version 1.0
 */
public class DuplicateManager {

	private static ThreadLocal<List<DuplicateModel>> 
					threadLocalList = new ThreadLocal<List<DuplicateModel>>() {
		// 该函数说明,在当前线程内,不管调用多次,只实例化一次
		protected synchronized List<DuplicateModel> initialValue() {
			return new ArrayList<DuplicateModel>();
		}
	};

	public static List<DuplicateModel> getCurrentThreadList() {
		return threadLocalList.get();
	}
	/**清空当前线程中设置进的list*/
	public static void removeCurrentThreadListValue(){
		threadLocalList.remove();
	}

	public static void main(String[] args) throws Exception {
		
		Thread thread1=new Thread(){
			public void run(){
				DuplicateManager.getCurrentThreadList().add(new DuplicateModel());
				System.out.println(DuplicateManager.getCurrentThreadList().size());
				DuplicateManager.removeCurrentThreadListValue();
				DuplicateManager.removeCurrentThreadListValue();
				System.out.println("当前线程的值被删除了."+DuplicateManager.getCurrentThreadList().size());
			}
		};
		
		
		Thread thread2=new Thread(){
			public void run(){
				System.out.println(DuplicateManager.getCurrentThreadList().size());
			}
		};
		
		thread1.start();
		Thread.sleep(1000L);
		thread2.start();
	
		System.out.println("-------------------------------");
		Runnable runnable1=new Runnable(){
			public void run(){
				DuplicateManager.getCurrentThreadList().add(new DuplicateModel());
				System.out.println(DuplicateManager.getCurrentThreadList().size());
			}
		};
		
		Thread thread3=new Thread(runnable1);
		Thread thread4=new Thread(runnable1);
		
		thread3.start();
		Thread.sleep(1000L);
		thread4.start();
	}
	
	
}

二, 设置一个model存储相同值的doc,并设置开关,只出现一次

 

/*
 * CopyRright (c)  www.fdauto.com
 */
package com.fdauto.bws.business.module.lucene.duplicate;

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

/**
 * 
 *用于存放一组具有相同值的字段
 * 
 * @author 09817(wu_quanyin)
 * @date 2011-01-06 上午17:02:44
 * @version 1.0
 */
public class DuplicateModel {

	
	private int mainDoc;
	//用于进行判断该重复值是否比较过,如果比较过则不在比较
	private boolean isChecked=false;
	private List<Integer> assistantDocs=new ArrayList<Integer>();
	
	public DuplicateModel(){}
	public DuplicateModel(int mainDoc){
		this.mainDoc=mainDoc;
	}
	
	public int getMainDoc() {
		return mainDoc;
	}
	public void setMainDoc(int mainDoc) {
		this.mainDoc = mainDoc;
	}
	public boolean isChecked() {
		return isChecked;
	}
	public void setChecked(boolean isChecked) {
		this.isChecked = isChecked;
	}
	public List<Integer> getAssistantDocs() {
		return assistantDocs;
	}
	public void setAssistantDocs(List<Integer> assistantDocs) {
		this.assistantDocs = assistantDocs;
	}
	
	
}

 三,扩展duplicatefilter类

 

 

/*
 * CopyRright (c)  www.fdauto.com
 */
package com.fdauto.bws.business.module.lucene.duplicate;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.OpenBitSet;

/**
 * 在对重复的项进行以集合的形式区分存放在list中待在DuplicateQuery进行比较
 * 
 * @author wu_quanyin(09817)
 * @version 1.0
 * @date 2011-01-06 上午10:54:01
 */
public class DuplicateExtendFilter extends Filter {

	private static final long serialVersionUID = 1601875802819099276L;

	String fieldName;

	public DuplicateExtendFilter(String fieldName) {
		this.fieldName = fieldName;
	}

	@Override
	public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
		return correctBits(reader);
	}

	private OpenBitSet correctBits(IndexReader reader) throws IOException {
	
		OpenBitSet bits = new OpenBitSet(reader.maxDoc()); // assume all are
															// INvalid
		Term startTerm = new Term(fieldName);
		TermEnum te = reader.terms(startTerm);
		if (te != null) {
			Term currTerm = te.term();
			while ((currTerm != null)
					&& (currTerm.field() == startTerm.field())) // term
																// fieldnames
																// are interned
			{
				int firstDoc = -1;

				// set non duplicates
				TermDocs td = reader.termDocs(currTerm);
				// 第一个全部添加
				if (td.next()) {
					firstDoc = td.doc();
					bits.set(firstDoc);
				}

				// --------------当有重复键时,实行对具有重复的进行保留比较
				DuplicateModel duplicateModel = new DuplicateModel();
				boolean isDuplicate = false;
				while (td.next()) {
					isDuplicate = true;
					duplicateModel.getAssistantDocs().add(td.doc());
				}
				if (isDuplicate) {
					duplicateModel.setMainDoc(firstDoc);
					duplicateModel.getAssistantDocs().add(firstDoc);
					DuplicateManager.getCurrentThreadList().add(duplicateModel);
				} else {
					duplicateModel = null;
				}
				// -----------------------

				if (!te.next()) {
					break;
				}
				currTerm = te.term();
			}
		}
		return bits;
	}

	public String getFieldName() {
		return fieldName;
	}

	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if ((obj == null) || (obj.getClass() != this.getClass()))
			return false;
		DuplicateExtendFilter other = (DuplicateExtendFilter) obj;
		return (fieldName == other.fieldName || (fieldName != null && fieldName
				.equals(other.fieldName)));
	}

	@Override
	public int hashCode() {
		int hash = 217;
		hash = 31 * hash + fieldName.hashCode();
		return hash;
	}
	

}
 

 

四,在query中,根据自己的逻辑进行判断,扩展filterquery类

 

/*
 * CopyRright (c)  www.fdauto.com
 */
package com.fdauto.bws.business.module.lucene.duplicate;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.FilteredQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.Similarity;
import org.apache.lucene.search.Weight;
import org.apache.lucene.util.ToStringUtils;

/**
 * 与DuplicateExtendFilter配合使用,
 * 对有重复的一个个比较过去..
 * 
 * @author 09817(wu_quanyin)
 * @date 2010-12-25 上午09:02:44
 * @version 1.0
 */
public class DuplicateQuery extends Query {

	/**
	 * 
	 */
	private static final long serialVersionUID = 4610299680666587077L;
	Query query;
	Filter filter;

	/**
	 * Constructs a new query which applies a filter to the results of the
	 * original query. Filter.getDocIdSet() will be called every time this query
	 * is used in a search.
	 * 
	 * @param query
	 *            Query to be filtered, cannot be <code>null</code>.
	 * @param filter
	 *            Filter to apply to query results, cannot be <code>null</code>.
	 */
	public DuplicateQuery(Query query, Filter filter) {
		this.query = query;
		this.filter = filter;
	}

	/**
	 * Returns a Weight that applies the filter to the enclosed query's Weight.
	 * This is accomplished by overriding the Scorer returned by the Weight.
	 */
	@Override
	public Weight createWeight(final Searcher searcher) throws IOException {
		final Weight weight = query.createWeight(searcher);
		final Similarity similarity = query.getSimilarity(searcher);
		return new Weight() {
			private static final long serialVersionUID = 3001781092877864947L;
			private float value;

			// pass these methods through to enclosed query's weight
			@Override
			public float getValue() {
				return value;
			}

			@Override
			public float sumOfSquaredWeights() throws IOException {
				return weight.sumOfSquaredWeights() * getBoost() * getBoost();
			}

			@Override
			public void normalize(float v) {
				weight.normalize(v);
				value = weight.getValue() * getBoost();
			}

			@Override
			public Explanation explain(IndexReader ir, int i)
					throws IOException {
				Explanation inner = weight.explain(ir, i);
				if (getBoost() != 1) {
					Explanation preBoost = inner;
					inner = new Explanation(inner.getValue() * getBoost(),
							"product of:");
					inner.addDetail(new Explanation(getBoost(), "boost"));
					inner.addDetail(preBoost);
				}
				Filter f = DuplicateQuery.this.filter;
				DocIdSet docIdSet = f.getDocIdSet(ir);
				DocIdSetIterator docIdSetIterator = docIdSet == null ? DocIdSet.EMPTY_DOCIDSET
						.iterator()
						: docIdSet.iterator();
				if (docIdSetIterator == null) {
					docIdSetIterator = DocIdSet.EMPTY_DOCIDSET.iterator();
				}
				if (docIdSetIterator.advance(i) == i) {
					return inner;
				} else {
					Explanation result = new Explanation(0.0f,
							"failure to match filter: " + f.toString());
					result.addDetail(inner);
					return result;
				}
			}

			// return this query
			@Override
			public Query getQuery() {
				return DuplicateQuery.this;
			}

			// return a filtering scorer
			@Override
			public Scorer scorer(IndexReader indexReader,
					boolean scoreDocsInOrder, boolean topScorer)
					throws IOException {
				final Scorer scorer = weight.scorer(indexReader, true, false);
				if (scorer == null) {
					return null;
				}
				DocIdSet docIdSet = filter.getDocIdSet(indexReader);
				if (docIdSet == null) {
					return null;
				}
				final DocIdSetIterator docIdSetIterator = docIdSet.iterator();

				if (docIdSetIterator == null) {
					return null;
				}

				return new Scorer(similarity) {

					private int doc = -1;

					private int advanceToCommon(int scorerDoc, int disiDoc)
							throws IOException {
						while (scorerDoc != disiDoc) {
							if (scorerDoc < disiDoc) {

								scorerDoc = scorer.advance(disiDoc);
							} else {
								disiDoc = docIdSetIterator.advance(scorerDoc);
							}

						}
						return scorerDoc;
					}

					@Override
					public int nextDoc() throws IOException {
						int scorerDoc = -1;
						
						//对每一个重复的进行比较
						while ((scorerDoc = scorer.nextDoc()) != NO_MORE_DOCS) {
							
							boolean ignoreDocment=false;
							
							for (Iterator<DuplicateModel> duplicateIterator = DuplicateManager
									.getCurrentThreadList().iterator(); duplicateIterator
									.hasNext();) {
								DuplicateModel duplicateModel = duplicateIterator.next();
								if(duplicateModel.getAssistantDocs()
											.contains(scorerDoc)){
									if(!duplicateModel.isChecked()){
										duplicateModel.setChecked(true);
										return scorerDoc;
									}else{
										//如果已经被检查过的忽略
										ignoreDocment=true;
										break;
									}
								}
								
							}
							
							// 如果该doc已经加入过,则忽略
							if (ignoreDocment) {
								continue;
							}

							return scorerDoc;

						}
						return NO_MORE_DOCS;

					}

					@Override
					public int docID() {
						return doc;
					}

					@Override
					public int advance(int target) throws IOException {
						int disiDoc, scorerDoc;
						return doc = (disiDoc = docIdSetIterator
								.advance(target)) != NO_MORE_DOCS
								&& (scorerDoc = scorer.advance(disiDoc)) != NO_MORE_DOCS
								&& advanceToCommon(scorerDoc, disiDoc) != NO_MORE_DOCS ? scorer
								.docID()
								: NO_MORE_DOCS;
					}

					@Override
					public float score() throws IOException {
						return getBoost() * scorer.score();
					}
				};
			}
		};
	}

	/** Rewrites the wrapped query. */
	@Override
	public Query rewrite(IndexReader reader) throws IOException {
		Query rewritten = query.rewrite(reader);
		if (rewritten != query) {
			DuplicateQuery clone = (DuplicateQuery) this.clone();
			clone.query = rewritten;
			return clone;
		} else {
			return this;
		}
	}

	public Query getQuery() {
		return query;
	}

	public Filter getFilter() {
		return filter;
	}

	// inherit javadoc
	@Override
	public void extractTerms(Set<Term> terms) {
		getQuery().extractTerms(terms);
	}

	/** Prints a user-readable version of this query. */
	@Override
	public String toString(String s) {
		StringBuilder buffer = new StringBuilder();
		buffer.append("filtered(");
		buffer.append(query.toString(s));
		buffer.append(")->");
		buffer.append(filter);
		buffer.append(ToStringUtils.boost(getBoost()));
		return buffer.toString();
	}

	/** Returns true iff <code>o</code> is equal to this. */
	@Override
	public boolean equals(Object o) {
		if (o instanceof FilteredQuery) {
			DuplicateQuery fq = (DuplicateQuery) o;
			return (query.equals(fq.query) && filter.equals(fq.filter) && getBoost() == fq
					.getBoost());
		}
		return false;
	}

	/** Returns a hash code value for this object. */
	@Override
	public int hashCode() {
		return query.hashCode() ^ filter.hashCode()
				+ Float.floatToRawIntBits(getBoost());
	}
}
使用:
DuplicateExtendFilter filter = new DuplicateExtendFilter(
					uniqueField);
			duplicateQuery = new DuplicateQuery(query, filter);
分享到:
评论
5 楼 skambc 2011-10-19  
wu_quanyin 写道
skambc 写道
lucene提供的DuplicateFilter,在实际应用感觉没有什么实际意义,因为它只是在重复的域内保留了一个文档,造成查询数据丢失。提供这个真是没什么用呀

没错,,所以我对的进行了改造,按我以上的设置,可以达到想要的效果,不过在性能上会有所消耗。

你好,我qq499530853,方便的话加我一下,最近用lucene,咨询点东西,谢了
4 楼 wu_quanyin 2011-10-19  
skambc 写道
lucene提供的DuplicateFilter,在实际应用感觉没有什么实际意义,因为它只是在重复的域内保留了一个文档,造成查询数据丢失。提供这个真是没什么用呀

没错,,所以我对的进行了改造,按我以上的设置,可以达到想要的效果,不过在性能上会有所消耗。
3 楼 skambc 2011-10-19  
lucene提供的DuplicateFilter,在实际应用感觉没有什么实际意义,因为它只是在重复的域内保留了一个文档,造成查询数据丢失。提供这个真是没什么用呀
2 楼 wu_quanyin 2011-10-11  
confident_f 写道
通过你写的这篇文章,可以看出你对lucene的一套机制肯定做了深入的研究,关于lucene的去重问题,我想请教你一个问题,它去重的具体过程是怎么样的?
比如在search的时候search(query,n) 是把n里的去掉重复的吗?
谢谢

要了解这个问题,你可以先了解下我以前的提问文章,
http://www.iteye.com/problems/56869
1 楼 confident_f 2011-10-11  
通过你写的这篇文章,可以看出你对lucene的一套机制肯定做了深入的研究,关于lucene的去重问题,我想请教你一个问题,它去重的具体过程是怎么样的?
比如在search的时候search(query,n) 是把n里的去掉重复的吗?
谢谢

相关推荐

    lucene4.10

    Lucene 4.10是Apache Lucene项目的一个重要版本,它是一个高性能、全文本搜索引擎库,广泛应用于各种信息检索系统中。这个版本在索引效率、查询性能以及搜索精度上都有显著提升,为开发者提供了强大的文本处理能力。...

    基于OpenSource的全文检索框架

    Jakarta Lucene是Apache基金会旗下的一个开源项目,旨在提供高性能的全文检索服务。不同于传统的数据库模糊查询,Lucene具有更高的性能,并能进行相似度计算及去重操作。Lucene支持多种编程语言版本,包括Java、C和...

    基于lucene的索引与搜索

    基于Lucene的索引与搜索技术,不仅涉及到数据的高效存储和检索,还包括了文本预处理、分词、相关性排序等多个环节。 第二章 搜索引擎的结构 2.1 系统概述 搜索引擎主要由三部分组成:网络爬虫(也称为网络机器人...

    Lucene3.0之查询类型详解

    在Lucene3.0中,查询处理是一个关键环节,涉及多种查询方式和理论模型。以下是对这些概念的详细解释: 1. **查询方式**: - **顺序查询**:是最简单的查询方式,直接遍历索引,效率较低。 - **索引查询**:基于预...

    开发自己的搜索引擎 lucene + heritrix

    开发自己的搜索引擎是一项复杂且具有挑战性的任务,涉及信息检索、数据处理、网络爬虫等多个领域的知识。在这个过程中,Lucene 和 Heritrix 是两个非常关键的工具,它们分别在搜索引擎的构建中扮演着不同的角色。 ...

    Lucene搜索引擎开发权威经典11-14.rar

    《Lucene搜索引擎开发权威经典11-14》是一本深度剖析Lucene搜索引擎技术的专业书籍,专注于讲解如何利用Lucene进行高效、精准的全文检索。该书以Lucene的2.1版本为背景,深入浅出地介绍了从基础概念到实际开发应用的...

    基于Python的网络新闻爬虫与检索.pdf

    - Solr:是一个基于Lucene的搜索服务器,提供了全文检索功能,可用于提高检索速度和准确性。 网络新闻爬虫与检索系统的设计与实现,需要考虑的问题包括但不限于: - 如何高效地从众多新闻门户网站中抓取新闻信息; ...

    Lucene+Heritrix(搜索引擎开发)

    Lucene是一个高性能、可伸缩、可扩展的全文检索库,它是用Java编写的开源项目。Lucene的目的是为软件开发人员提供一个简单易用的API,使得他们能够在自己的应用程序中加入全文搜索功能。Lucene可以用于全文搜索、...

    lucene学习笔记

    Lucene.NET 是一个高性能、全功能的文本搜索引擎库,它为.NET平台提供了一个灵活且强大的全文检索解决方案。该库允许开发者将搜索功能集成到应用程序中,而无需了解复杂的搜索算法和技术细节。 在本节中,我们将...

    Lucene+Heritrix 源码

    Lucene 是由 Apache 软件基金会开发的一个全文检索库,它提供了强大的文本分析、索引构建和搜索功能。在Lucene 2.0版本中,它引入了更高效的倒排索引结构,支持多字段搜索,并且优化了内存使用和搜索性能。通过阅读...

    Lucene.Nutch搜索引擎开发

    Lucene是一个高性能、全文本搜索库,而Nutch则是一个基于Lucene的开源网络爬虫项目,两者结合可以构建强大的互联网搜索引擎。 1. **Lucene**: Lucene是Apache软件基金会的一个项目,提供了一个高级的、完全基于Java...

    开发自己的搜索引擎lucene+heritrix(第2版)(heritrixProject源码)

    在IT领域,构建一个自定义的搜索引擎是一项技术挑战,但也是探索信息检索和大数据处理的有趣实践。"开发自己的搜索引擎lucene+heritrix(第2版)(heritrixProject源码)"是一个教程或者项目,旨在指导用户如何利用...

    人工智能-项目实践-搜索引擎-豆瓣音乐搜索引擎

    2. Elasticsearch:一个高性能的全文搜索引擎,支持分布式、实时的数据存储和检索,适合处理大规模数据。 3. Lucene:Elasticsearch底层依赖于Lucene库,提供文本分析、索引和搜索的功能。 4. 数据库技术:如MySQL...

    Scrapy-Redis分布式爬虫与搜索网站构建-搜索引擎论文-图书档案学论文.docx

    它提供了全文检索、实时分析等功能,非常适合用来构建搜索引擎。具体步骤包括: - **数据导入**:将爬取到的数据导入到ElasticSearch中。 - **索引创建**:根据数据的特点创建相应的索引,提高查询效率。 - **查询...

    去哪儿搜索引擎QSearch设计与实现

    搜索引擎是一种根据特定策略,利用计算机程序从互联网上收集信息,并对其进行整理和处理,最终为用户提供检索服务的系统。用户通过输入关键词来获取相关的搜索结果。搜索引擎的类型多样,包括但不限于全文索引、目录...

    使用C#开发搜索引擎PPT

    LUCENE.NET是Apache Lucene的.NET版本,是一个高性能、全文本搜索库。它提供了高级的索引和搜索功能,适用于各种应用,包括网站、数据库、文档检索等。主要知识点包括: - **索引创建**:学习如何使用LUCENE.NET对...

    nutch-1.9 源码

    它集成了Lucene库,提供高效的全文检索功能。 8. **插件体系**:Nutch的灵活性来源于其强大的插件体系。开发者可以编写自定义插件来扩展其功能,如改变抓取策略、定制解析规则等。 9. **配置文件**:Nutch的配置...

Global site tag (gtag.js) - Google Analytics