- 浏览: 208256 次
- 性别:
- 来自: 福建省
文章分类
最新评论
-
c929833623:
...
Mysql JDBC驱动源码分析(Statement,ResultSet的创建)四 -
pythonlord:
顶 很有帮助,感谢楼主,好人一生平安
Mysql JDBC驱动源码分析(加载驱动)一 -
kiaonly:
代码有错误,我戳。
解释器模式(Interpreter)---java与模式(例子) -
wyzxzws:
小鸟学习了!
JAVA编码问题记录 -
xiaotao.2010:
写的不错! 弱弱说一句 建议使用URL二次转码, 这样可以避免 ...
JAVA编码问题记录
在处理如"问答"功能时,以答进行搜索,这时假就会出现去重问题--->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里的去掉重复的吗?
谢谢
比如在search的时候search(query,n) 是把n里的去掉重复的吗?
谢谢
要了解这个问题,你可以先了解下我以前的提问文章,
http://www.iteye.com/problems/56869
1 楼
confident_f
2011-10-11
通过你写的这篇文章,可以看出你对lucene的一套机制肯定做了深入的研究,关于lucene的去重问题,我想请教你一个问题,它去重的具体过程是怎么样的?
比如在search的时候search(query,n) 是把n里的去掉重复的吗?
谢谢
比如在search的时候search(query,n) 是把n里的去掉重复的吗?
谢谢
相关推荐
Lucene 4.10是Apache Lucene项目的一个重要版本,它是一个高性能、全文本搜索引擎库,广泛应用于各种信息检索系统中。这个版本在索引效率、查询性能以及搜索精度上都有显著提升,为开发者提供了强大的文本处理能力。...
Jakarta Lucene是Apache基金会旗下的一个开源项目,旨在提供高性能的全文检索服务。不同于传统的数据库模糊查询,Lucene具有更高的性能,并能进行相似度计算及去重操作。Lucene支持多种编程语言版本,包括Java、C和...
基于Lucene的索引与搜索技术,不仅涉及到数据的高效存储和检索,还包括了文本预处理、分词、相关性排序等多个环节。 第二章 搜索引擎的结构 2.1 系统概述 搜索引擎主要由三部分组成:网络爬虫(也称为网络机器人...
在Lucene3.0中,查询处理是一个关键环节,涉及多种查询方式和理论模型。以下是对这些概念的详细解释: 1. **查询方式**: - **顺序查询**:是最简单的查询方式,直接遍历索引,效率较低。 - **索引查询**:基于预...
开发自己的搜索引擎是一项复杂且具有挑战性的任务,涉及信息检索、数据处理、网络爬虫等多个领域的知识。在这个过程中,Lucene 和 Heritrix 是两个非常关键的工具,它们分别在搜索引擎的构建中扮演着不同的角色。 ...
《Lucene搜索引擎开发权威经典11-14》是一本深度剖析Lucene搜索引擎技术的专业书籍,专注于讲解如何利用Lucene进行高效、精准的全文检索。该书以Lucene的2.1版本为背景,深入浅出地介绍了从基础概念到实际开发应用的...
- Solr:是一个基于Lucene的搜索服务器,提供了全文检索功能,可用于提高检索速度和准确性。 网络新闻爬虫与检索系统的设计与实现,需要考虑的问题包括但不限于: - 如何高效地从众多新闻门户网站中抓取新闻信息; ...
Lucene是一个高性能、可伸缩、可扩展的全文检索库,它是用Java编写的开源项目。Lucene的目的是为软件开发人员提供一个简单易用的API,使得他们能够在自己的应用程序中加入全文搜索功能。Lucene可以用于全文搜索、...
Lucene.NET 是一个高性能、全功能的文本搜索引擎库,它为.NET平台提供了一个灵活且强大的全文检索解决方案。该库允许开发者将搜索功能集成到应用程序中,而无需了解复杂的搜索算法和技术细节。 在本节中,我们将...
Lucene 是由 Apache 软件基金会开发的一个全文检索库,它提供了强大的文本分析、索引构建和搜索功能。在Lucene 2.0版本中,它引入了更高效的倒排索引结构,支持多字段搜索,并且优化了内存使用和搜索性能。通过阅读...
Lucene是一个高性能、全文本搜索库,而Nutch则是一个基于Lucene的开源网络爬虫项目,两者结合可以构建强大的互联网搜索引擎。 1. **Lucene**: Lucene是Apache软件基金会的一个项目,提供了一个高级的、完全基于Java...
在IT领域,构建一个自定义的搜索引擎是一项技术挑战,但也是探索信息检索和大数据处理的有趣实践。"开发自己的搜索引擎lucene+heritrix(第2版)(heritrixProject源码)"是一个教程或者项目,旨在指导用户如何利用...
2. Elasticsearch:一个高性能的全文搜索引擎,支持分布式、实时的数据存储和检索,适合处理大规模数据。 3. Lucene:Elasticsearch底层依赖于Lucene库,提供文本分析、索引和搜索的功能。 4. 数据库技术:如MySQL...
它提供了全文检索、实时分析等功能,非常适合用来构建搜索引擎。具体步骤包括: - **数据导入**:将爬取到的数据导入到ElasticSearch中。 - **索引创建**:根据数据的特点创建相应的索引,提高查询效率。 - **查询...
搜索引擎是一种根据特定策略,利用计算机程序从互联网上收集信息,并对其进行整理和处理,最终为用户提供检索服务的系统。用户通过输入关键词来获取相关的搜索结果。搜索引擎的类型多样,包括但不限于全文索引、目录...
LUCENE.NET是Apache Lucene的.NET版本,是一个高性能、全文本搜索库。它提供了高级的索引和搜索功能,适用于各种应用,包括网站、数据库、文档检索等。主要知识点包括: - **索引创建**:学习如何使用LUCENE.NET对...
它集成了Lucene库,提供高效的全文检索功能。 8. **插件体系**:Nutch的灵活性来源于其强大的插件体系。开发者可以编写自定义插件来扩展其功能,如改变抓取策略、定制解析规则等。 9. **配置文件**:Nutch的配置...