短语查询不起作用 Lucene 4.5.0.



我试图使用PhraseQuery但无法从搜索中获得命中。我正在使用Lucene 4.5.0.

我的索引代码

private IndexWriter writer;
public LuceneIndexSF(final String indexDir) throws IOException {
    Analyzer analyzer = new KeywordAnalyzer();
    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_45,
            analyzer);
    Directory directory = FSDirectory.open(new File(indexDir));
    writer = new IndexWriter(directory, config);
}
private Document getDocument(File f, String line, int lineNum)
            throws IOException {
        Document doc = new Document();
        Field field = null;
        if (line != null && line.split(DELIMITER).length >= 5) {
            String[] lineValues = line.split(DELIMITER);
            field = new Field("name", line.split("t")[1],
                    TextField.TYPE_STORED);
            doc.add(field);
            if (lineValues[2] != null && !lineValues[2].trim().isEmpty()) {
                field = new Field("ref", lineValues[2], TextField.TYPE_STORED);
                doc.add(field);
            }
            field = new Field("type", lineValues[3], TextField.TYPE_STORED);
            doc.add(field);
            field = new LongField("code", Long.parseLong(lineValues[4]),
                    LongField.TYPE_STORED);
            doc.add(field);
            if (lineValues.length == 7 && lineValues[5] != null
                    && !lineValues[5].trim().isEmpty()) {
                field = new Field("alias1", lineValues[5],
                        TextField.TYPE_STORED);
                doc.add(field);
            }
            if (lineValues.length == 7 && lineValues[6] != null
                    && !lineValues[6].trim().isEmpty()) {
                field = new Field("alias2", lineValues[6],
                        TextField.TYPE_STORED);
                doc.add(field);
            }
        }
        field = new IntField("linenum", lineNum, IntField.TYPE_STORED);
        doc.add(field);
        return doc;
    }
.... and other code where i add document in writer using writer.addDocument(doc);

我的搜索代码

private static void search(String indexDir, String quer) throws IOException,
        ParseException {
    IndexReader inxRead = DirectoryReader.open(FSDirectory.open(new File(
            indexDir)));
    IndexSearcher is = new IndexSearcher(inxRead);
    String[] termArr = quer.split(" ");
    PhraseQuery phraseQuery= new PhraseQuery();
    for(int inx = 0; inx < termArr.length; inx++){
        phraseQuery.add(new Term("name", termArr[inx]));
    }
    phraseQuery.setSlop(4);
    long start = System.currentTimeMillis();
    TopDocs hits = is.search(phraseQuery, 1000);
    long end = System.currentTimeMillis();
    System.err.println("Parser> Found " + hits.totalHits
            + " document(s) (in " + (end - start)
            + " milliseconds) that matched query '" + multiQuery + "':");
    for (ScoreDoc scoreDoc : hits.scoreDocs) {
        Document doc = is.doc(scoreDoc.doc);
        System.out.println("Parser> " + scoreDoc.score + " :: "
                + doc.get("type") + " - " + doc.get("code") + " - "
                + doc.get("name") + ", " + doc.get("linenum"));
    }
    inxRead.close();
}

如果我做错了什么,请告诉我。

编辑

也尝试使用标准分析仪仍然没有结果

Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_45);

溶液

根据 Arun 的回答PhraseQuery正常工作需要分析器,它标记Document Field中的每个单词,对于我的情况,我LowerCaseFilter将所有查询小写,以便它可以在没有区分大小写的情况下工作。并用于自动完成目的的EdgeNGramTokenFilter

public LuceneIndexSF(final String indexDir) throws IOException {
Analyzer analyzer = new Analyzer() {
        @Override
        protected TokenStreamComponents createComponents(String fieldName,
                java.io.Reader reader) {
            Tokenizer source = new StandardTokenizer(Version.LUCENE_45,
                    reader);
            TokenStream result = new StandardFilter(Version.LUCENE_45,
                    source);
            result = new LowerCaseFilter(Version.LUCENE_45, result);
            result = new EdgeNGramTokenFilter(Version.LUCENE_45, result, 1,
                    20);
            return new TokenStreamComponents(source, result);
        }
    };
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_45,
        analyzer);
Directory directory = FSDirectory.open(new File(indexDir));
writer = new IndexWriter(directory, config);
}

我的最终搜索方法

private static void search(String indexDir, String quer) throws IOException,
    ParseException {
IndexReader inxRead = DirectoryReader.open(FSDirectory.open(new File(
        indexDir)));
IndexSearcher is = new IndexSearcher(inxRead);
String[] termArr = quer.split(" ");
PhraseQuery query1 = new PhraseQuery();
PhraseQuery query2 = new PhraseQuery();
PhraseQuery query3 = new PhraseQuery();
for (int inx = 0; inx < termArr.length; inx++) {
    query1.add(new Term(SchoolFinderConstant.ENTITY_NAME,termArr[inx]),inx);
    query2.add(new Term(SchoolFinderConstant.ENTITY_ALIAS1,termArr[inx]),inx);
    query3.add(new Term(SchoolFinderConstant.ENTITY_ALIAS2,termArr[inx]),inx);
}
BooleanQuery mainQuery = new BooleanQuery();
mainQuery.add(query1, Occur.SHOULD);
mainQuery.add(query2, Occur.SHOULD);
mainQuery.add(query3, Occur.SHOULD);
long start = System.currentTimeMillis();
TopDocs hits = is.search(mainQuery, 1000);
long end = System.currentTimeMillis();
System.err.println("Parser> Found " + hits.totalHits
        + " document(s) (in " + (end - start)
        + " milliseconds) that matched query '" + multiQuery + "':");
for (ScoreDoc scoreDoc : hits.scoreDocs) {
    Document doc = is.doc(scoreDoc.doc);
    System.out.println("Parser> " + scoreDoc.score + " :: "
            + doc.get("type") + " - " + doc.get("code") + " - "
            + doc.get("name") + ", " + doc.get("linenum"));
}
inxRead.close();
}

我用关键字分析器玩过你的代码,显然它不起作用,因为关键字分析器将整个流"标记化"为单个令牌。这对于邮政编码、ID 和某些产品名称等数据非常有用。http://lucene.apache.org/core/4_5_0/analyzers-common/org/apache/lucene/analysis/core/KeywordAnalyzer.html ,为此,您需要指定整个令牌而不进行任何更改。

然后我使用WhitespaceAnalyzer,它可以工作,并且能够为您的PhraseQuery找到匹配项。其余代码没有变化。让我知道这是否对您有用。

搜索与 MultiFieldQueryParser 一起使用的原因是,在查询时,您被迫使用与您的索引匹配的分析器。 简而言之,您需要确保索引分析器和查询时间分析器相似。

最新更新