`

MoreLikeThis实现检索相似文档

阅读更多

输入“related:doc_id”返回索引库中的相关文档

public static void main(String[] args) throws IOException {
 FSDirectory directory = FSDirectory.open(new File("D:\\DATAMANAGER\\INDEX\\SYS_3000"));
 IndexReader r = IndexReader.open(directory);
 MoreLikeThis mlt = new MoreLikeThis(r);
 mlt.setFieldNames(new String[]{"docName","content"});
 mlt.setMaxQueryTerms(5);
 String queryString = "related:18";
 if(queryString.startsWith("related:")){
//docId对应lucene内部的Doc.id字段,一般我们先通过检索一次获取到Lucene内部的docNum然后再根据这个docNum调用MoreLikeThis提供的接口(看了一下solr的MoreLikeThis组件的实现代码,其也是采用这种思想。不过它支持query查询多个docNum,然后再把每个docNum通过like方法去检索出的结果合在一起)
  int docId = Integer.parseInt(queryString.substring(8));
  System.out.println(docId+":"+r.isDeleted(docId));
  if(!r.isDeleted(docId)){
   Query query = mlt.like(docId);
   System.out.println("query:"+query.toString());
   IndexSearcher searcher = new IndexSearcher(r);
   TopDocs topDocs = searcher.search(query, 10);
   ScoreDoc[] sd = topDocs.scoreDocs;
   for(int i=0;i<sd.length;i++){
    Document d = searcher.doc(sd[i].doc);
    System.out.println(d.getField("docId").stringValue()+"="+d.get("docName"));
   }
      }
     }
}
1、为何找不到MoreLikeTihs的jar包?

    使用org.apache.lucene.search.similar包的MoreLikeThis类。在Lucene 1.9它属于外部包"similarity",从Lucene 2.1起,它属于新的外部包"queries"。

    在contrib\queries目录下的lucene-queries-3.0.2.jar

2、like(int docNum)帮你做了什么?

     like(int docNum)它首先根据传入的docNum找出该doc里的高频terms,然后用这些高频terms生成Queue,最后把Queue传进search方法得到最后结果。它的主要思想就是认为这些高频terms足以表示doc信息,然后通过搜索得到最后与此doc类似的结果。

下面为网上转载的一篇文章,引自:http://hi.baidu.com/savagert/blog/item/060d0d0974387c346b60fb1b.html

Leveraging term vectors
所谓term vector, 就是对于documents的某一field,如title,body这种文本类型的, 建立词频的多维向量空间.每一个词就是一维, 这维的值就是这个词在这个field中的频率.

如果你要使用term vectors, 就要在indexing的时候对该field打开term vectors的选项:

Field options for term vectors
TermVector.YES – record the unique terms that occurred, and their counts, in each document, but do not store any positions or offsets information.
TermVector.WITH_POSITIONS – record the unique terms and their counts, and also the positions of each occurrence of every term, but no offsets.
TermVector.WITH_OFFSETS – record the unique terms and their counts, with the offsets (start & end character position) of each occurrence of every term, but no positions.
TermVector.WITH_POSITIONS_OFFSETS – store unique terms and their counts, along with positions and offsets.
TermVector.NO – do not store any term vector information.
If Index.NO is specified for a field, then you must also specify TermVector.NO.

这样在index完后, 给定这个document id和field名称, 我们就可以从IndexReader读出这个term vector(前提是你在indexing时创建了terms vector):
TermFreqVector termFreqVector = reader.getTermFreqVector(id, "subject");
你可以遍历这个TermFreqVector去取出每个词和词频, 如果你在index时选择存下offsets和positions信息的话, 你在这边也可以取到.

有了这个term vector我们可以做一些有趣的应用:
1) Books like this
比较两本书是否相似,把书抽象成一个document文件, 具有author, subject fields. 那么现在就通过这两个field来比较两本书的相似度.
author这个field是multiple fields, 就是说可以有多个author, 那么第一步就是比author是否相同,
String[] authors = doc.getValues("author");
BooleanQuery authorQuery = new BooleanQuery(); // #3
for (int i = 0; i < authors.length; i++) { // #3
    String author = authors[i]; // #3
    authorQuery.add(new TermQuery(new Term("author", author)), BooleanClause.Occur.SHOULD); // #3
}
authorQuery.setBoost(2.0f);
最后还可以把这个查询的boost值设高, 表示这个条件很重要, 权重较高, 如果作者相同, 那么就很相似了.
第二步就用到term vector了, 这里用的很简单, 单纯的看subject field的term vector中的term是否相同,
TermFreqVector vector = // #4
reader.getTermFreqVector(id, "subject"); // #4
BooleanQuery subjectQuery = new BooleanQuery(); // #4
for (int j = 0; j < vector.size(); j++) { // #4
    TermQuery tq = new TermQuery(new Term("subject", vector.getTerms()[j]));
    subjectQuery.add(tq, BooleanClause.Occur.SHOULD); // #4
}

2) What category?
这个比上个例子高级一点, 怎么分类了,还是对于document的subject, 我们有了term vector.
所以对于两个document, 我们可以比较这两个文章的term vector在向量空间中的夹角, 夹角越小说明这个两个document越相似.
那么既然是分类就有个训练的过程, 我们必须建立每个类的term vector作为个标准, 来给其它document比较.
这里用map来实现这个term vector, (term, frequency), 用n个这样的map来表示n维. 我们就要为每个category来生成一个term vector, category和term vector也可以用一个map来连接.创建这个category的term vector, 这样做:
遍历这个类中的每个document, 取document的term vector, 把它加到category的term vector上.
private void addTermFreqToMap(Map vectorMap, TermFreqVector termFreqVector) {
    String[] terms = termFreqVector.getTerms();
    int[] freqs = termFreqVector.getTermFrequencies();
    for (int i = 0; i < terms.length; i++) {
        String term = terms[i];
        if (vectorMap.containsKey(term)) {
            Integer value = (Integer) vectorMap.get(term);
            vectorMap.put(term, new Integer(value.intValue() + freqs[i]));
        } else {
            vectorMap.put(term, new Integer(freqs[i]));
        }
   }
}
首先从document的term vector中取出term和frequency的list, 然后从category的term vector中取每一个term, 把document的term frequency加上去.OK了

有了这个每个类的category, 我们就要开始计算document和这个类的向量夹角了
cos = A*B/|A||B|
A*B就是点积, 就是两个向量每一维相乘, 然后全加起来.
这里为了简便计算, 假设document中term frequency只有两种情况, 0或1.就表示出现或不出现
private double computeAngle(String[] words, String category) {
    // assume words are unique and only occur once
    Map vectorMap = (Map) categoryMap.get(category);
    int dotProduct = 0;
    int sumOfSquares = 0;
    for (int i = 0; i < words.length; i++) {
        String word = words[i];
        int categoryWordFreq = 0;
        if (vectorMap.containsKey(word)) {
            categoryWordFreq = ((Integer) vectorMap.get(word)).intValue();
        }
        dotProduct += categoryWordFreq; // optimized because we assume frequency in words is 1
        sumOfSquares += categoryWordFreq * categoryWordFreq;
    }
    double denominator;
    if (sumOfSquares == words.length) {
        // avoid precision issues for special case
        denominator = sumOfSquares; // sqrt x * sqrt x = x
    } else {
        denominator = Math.sqrt(sumOfSquares) *
        Math.sqrt(words.length);
    }
    double ratio = dotProduct / denominator;
    return Math.acos(ratio);
}
这个函数就是实现了上面那个公式还是比较简单的.

3) MoreLikeThis

对于找到比较相似的文档,lucene还提供了个比较高效的接口,MoreLikeThis接口

http://lucene.apache.org/java/1_9_1/api/org/apache/lucene/search/similar/MoreLikeThis.html

对于上面的方法我们可以比较每两篇文档的余弦值,然后对余弦值进行排序,找出最相似的文档,但这个方法的最大问题在于计算量太大,当文档数目很大时,几乎是无法接受的,当然有专门的方法去优化余弦法,可以使计算量大大减少,但这个方法精确,但门槛较高。

这个接口的原理很简单,对于一篇文档中,我们只需要提取出interestingTerm(即tf×idf高的词),然后用lucene去搜索包含相同词的文档,作为相似文档,这个方法的优点就是高效,但缺点就是不准确,这个接口提供很多参数,你可以配置来选择interestingTerm。

MoreLikeThis mlt = new MoreLikeThis(ir);

Reader target = ...

// orig source of doc you want to find similarities to

Query query = mlt.like( target);

Hits hits = is.search(query);

用法很简单,这样就可以得到,相似的文档

这个接口比较灵活,你可以不直接用like接口,而是用
retrieveInterestingTerms(Reader r)

这样你可以获得interestingTerm,然后怎么处理就根据你自己的需要了


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/foamflower/archive/2010/12/01/6048667.aspx

分享到:
评论

相关推荐

    Wikipedia2Lucene:从HDFS导入Wikipedia XML转储到Lucene索引或Elasticsearch,并基于Lucene的MoreLikeThis查询检索类似的Wikipedia文章

    从HDFS导入Wikipedia XML转储到Lucene索引或Elasticsearch,并基于Lucene的MoreLikeThis查询检索类似的Wikipedia文章。 此应用程序是基于文本的文档相似性度量的实现,该度量被用作的研究中的基准度量。 将...

    Solr全文索引

    - **More Like This**:根据已知文档推荐相似的文档。 5. **C#项目集成** - **NuGet安装**:在C#项目中,可以通过NuGet包管理器安装SolrNet库,确保所有依赖项都已就绪。 - **配置连接**:设置Solr服务器的URL,...

    前端开源库-mongoose-mlt

    MongooseMLT(可能是Mongoose More Like This的缩写)填补了这一空白,它提供了更强大的搜索算法,使开发者能够对MongoDB中的数据进行更为精确和智能的匹配。 **MongoDB与全文搜索** MongoDB是一款流行的NoSQL...

    elasticsearch-中文开发指南

    - **More Like This API:** 查找与给定文档相似的其他文档。 **四、Java API** - **客户端:** Java 客户端提供了与 Elasticsearch 进行交互的便捷方式。 - **索引 API:** 创建或更新文档。 - **获取 API:** 检索...

    ElasticSearch可扩展的开源弹性搜索解决方案.docx

    - **more_like_this**:查找与提供的文本相似的文档。 - **more_like_this_field**:类似于 more_like_this,但仅应用于单个字段。 - **range**:在数值型或字符串型字段上进行范围查询。 ##### D. 过滤查询结果 -...

    PyPI 官网下载 | scorched-0.3.zip

    3. **查询接口**:提供简单和复杂的查询构造器,支持 Lucene 查询语法和 Solr 的 Faceting、Highlighting、MoreLikeThis 等高级功能。 4. **结果处理**:返回查询结果时,Scorched 可以解析 Solr 的 JSON 或 XML ...

    php_solr.dll ,php5.3版本

    - **高级搜索特性**:支持 faceting(分类统计)、highlighting(高亮)、more like this(相似推荐)等 Solr 提供的高级搜索特性。 - **优化与提交**:对索引进行优化,确保数据的一致性,并控制何时将更改提交到 ...

    分布式搜索 elasticsearch 方案研究 - Java API

    More Like This (MLT) 功能能够根据现有文档内容找到相似的文档, 适用于实现基于内容的推荐系统。 ##### 8.1 MLT 查询 - **步骤**: 1. 创建 SearchRequest 对象。 2. 设置索引名称和文档类型。 3. 使用 ...

Global site tag (gtag.js) - Google Analytics