【问题标题】:Calculate Matching String percent in lucene计算lucene中的匹配字符串百分比
【发布时间】:2015-11-04 12:43:24
【问题描述】:

我在我的 java 应用程序中使用了 Lucene 算法来从索引中找出匹配的字符串。 我已经从所有点击中获取了前 5 个顶级文档,但我想检查或计算原始字符串和匹配字符串的匹配存在。 在Lucene中可以吗? Lucene 有什么方法可以找出来吗? 例如:-

    original string = I am good.

    matching string = am good.

    % of matching = 95    

【问题讨论】:

    标签: java lucene


    【解决方案1】:

    当您说匹配百分比时,您是什么意思?如果您想知道结果文档中包含多少个原始文本(例如,在您的情况下是 3 个中的 2 个) 然后您可以使用term vectors 来完成工作,获取字段和文档的术语向量并迭代术语并查看您要查找的内容中是否有术语。甚至您可以存储字符串并获取整个内容并进行数学计算(如果存储不是问题)。 当前的 lucene 使用vector space model(将从版本 6x 更改为 BM25)计算分数,并通过ScroeDoc 为您提供匹配分数 但是 score doc 给出了十进制值,如果足够了就使用它。

    如果这不能回答问题,请提供有关如何使用样本进行计算的更多详细信息。

    希望这会有所帮助。

    PS,我已经写了简单的脚本,所以你可以看到并根据你的需要更正它:

    package org.query;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.TokenStream;
    import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
    import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    import org.apache.lucene.document.FieldType;
    import org.apache.lucene.index.*;
    import org.apache.lucene.search.*;
    import org.apache.lucene.store.RAMDirectory;
    import org.apache.lucene.util.BytesRef;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * Created by ekamolid on 11/2/2015.
     */
    public class LevenshteinTest {
        private RAMDirectory directory;
        private IndexSearcher searcher;
        private IndexReader reader;
        private Analyzer analyzer;
    
        @Before
        public void setUp() throws Exception {
            directory = new RAMDirectory();
    
            analyzer = new WhitespaceAnalyzer();
            IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(analyzer));
    
            Document doc = new Document();
            FieldType fieldType = new FieldType();
            fieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
            fieldType.setStoreTermVectors(true);
            doc.add(new Field("f", "the quick brown fox jumps over the lazy dog", fieldType));
            writer.addDocument(doc);
    
            doc = new Document();
            doc.add(new Field("f", "the quick red fox jumps over the sleepy cat", fieldType));
            writer.addDocument(doc);
    
            doc = new Document();
            doc.add(new Field("f", "quiick caar went xyztz dog", fieldType));
            writer.addDocument(doc);
    
            writer.close();
    
            reader = DirectoryReader.open(directory);
            searcher = new IndexSearcher(reader);
        }
    
        public static int distance(String a, String b) { //code is taken from http://rosettacode.org/wiki/Levenshtein_distance#Java
            a = a.toLowerCase();
            b = b.toLowerCase();
            // i == 0
            int[] costs = new int[b.length() + 1];
            for (int j = 0; j < costs.length; j++)
                costs[j] = j;
            for (int i = 1; i <= a.length(); i++) {
                // j == 0; nw = lev(i - 1, j)
                costs[0] = i;
                int nw = i - 1;
                for (int j = 1; j <= b.length(); j++) {
                    int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1);
                    nw = costs[j];
                    costs[j] = cj;
                }
            }
            return costs[b.length()];
        }
    
    
        @Test
        public void test1() throws Exception {
            String s = "quick caar dog";
            TokenStream tokenStream = analyzer.tokenStream("abc", s);
            TermToBytesRefAttribute termAttribute = tokenStream.getAttribute(TermToBytesRefAttribute.class);
            Set<String> stringSet = new HashSet<>();
            tokenStream.reset();
            BooleanQuery.Builder builder = new BooleanQuery.Builder();
            while (tokenStream.incrementToken()) {
                stringSet.add(termAttribute.getBytesRef().utf8ToString());
                Query query = new FuzzyQuery(new Term("f", termAttribute.getBytesRef().utf8ToString()), 2); //search only 2 edits
                builder.add(query, BooleanClause.Occur.SHOULD);
            }
            TopDocs hits = searcher.search(builder.build(), 10);
            int exactMatch = 0;
            int match1 = 0;
            int match2 = 0;
            for (ScoreDoc scoreDoc : hits.scoreDocs) {
                exactMatch = match1 = match2 = 0;
                Terms terms = reader.getTermVector(scoreDoc.doc, "f");
                TermsEnum termsEnum = terms.iterator();
                while (true) {
                    BytesRef bytesRef = termsEnum.next();
                    if (bytesRef == null) {
                        break;
                    }
                    String str = bytesRef.utf8ToString();
                    if (stringSet.contains(str)) {
                        exactMatch++;
                        continue;
                    }
                    for (String s1 : stringSet) {
                        int distance = distance(s1, str);
                        if (distance <= 1) {
                            match1++;
                        } else if (distance <= 2) {
                            match2++;
                        }
                    }
                }
                System.out.print(" doc=" + scoreDoc.doc);
                System.out.print(" exactMatch=" + exactMatch);
                System.out.print(" match1=" + match1);
                System.out.println(" match2=" + match1);
            }
        }
    }
    

    我得到的输出是:

     doc=2 exactMatch=2 match1=1 match2=1
     doc=1 exactMatch=1 match1=0 match2=0
     doc=0 exactMatch=2 match1=0 match2=0
    

    这是工作代码,它告诉有多少个字符是完全匹配的,其中有多少是 1 char 差异和 2 char 差异。所以你可以把你的登录信息放在那里,根据你手头的数字计算百分比。由于您正在迭代文档,因此这可能会慢一些,但您应该将结果限制在某个数字(示例中为10),这样它就不会很慢。

    【讨论】:

    • 谢谢先生的帮助。先生,术语向量用于匹配每个术语,例如“好女孩”匹配“好”和“女孩”,但是如果我的输入字符串中有任何语音错误怎么办。例如:-“god grl”匹配“好女孩”那么我怎样才能找到匹配的字符串百分比?
    猜你喜欢
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 2023-03-22
    • 2021-02-05
    • 2019-07-07
    • 1970-01-01
    • 2012-02-29
    • 2019-07-11
    相关资源
    最近更新 更多