【问题标题】:Lucene query with numeric field does not find anything带有数字字段的 Lucene 查询未找到任何内容
【发布时间】:2014-05-21 07:55:20
【问题描述】:

我试图了解 lucene 查询语法是如何工作的,所以我编写了这个小程序。 使用 NumericRangeQuery 时,我可以找到我想要的文档,但是在尝试解析搜索条件时,它找不到任何匹配项,尽管我使用的是相同的条件。 我知道分析器可以解释差异,但使用的 StandardAnalyzer 不会删除数值。

谁能告诉我我做错了什么? 谢谢。

package org.burre.lucene.matching;

import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.*;
import org.apache.lucene.util.Version;

public class SmallestEngine {
  private static final Version VERSION=Version.LUCENE_48;
  private StandardAnalyzer analyzer = new StandardAnalyzer(VERSION);
  private Directory index = new RAMDirectory();

  private Document buildDoc(String name, int beds) {
    Document doc = new Document();
    doc.add(new StringField("name", name, Field.Store.YES));
    doc.add(new IntField("beds", beds, Field.Store.YES));
    return doc;
  }

  public void buildSearchEngine() throws IOException {
    IndexWriterConfig config = new IndexWriterConfig(VERSION,
            analyzer);

    IndexWriter w = new IndexWriter(index, config);
    // Generate 10 houses with 0 to 3 beds
    for (int i=0;i<10;i++)
        w.addDocument(buildDoc("house"+(100+i),i % 4));
    w.close();
  }
  /**
   * Execute the query and show the result
   */
  public void search(Query q) throws IOException {
    System.out.println("executing query\""+q+"\"");
    IndexReader reader = DirectoryReader.open(index);
    try {
        IndexSearcher searcher = new IndexSearcher(reader);
        ScoreDoc[] hits = searcher.search(q, 10).scoreDocs;
        System.out.println("Found " + hits.length + " hits.");
        for (int i = 0; i < hits.length; ++i) {
            int docId = hits[i].doc;
            Document d = searcher.doc(docId);
            System.out.println(""+(i+1)+". " + d.get("name") + ", beds:"
                    + d.get("beds"));
        }
    } finally {
        if (reader != null)
            reader.close();
    }
  }

  public static void main(String[] args) throws IOException, ParseException {
    SmallestEngine me = new SmallestEngine();
    me.buildSearchEngine();
    System.out.println("SearchByRange");
    me.search(NumericRangeQuery.newIntRange("beds", 3, 3,true,true));
    System.out.println("-----------------");
    System.out.println("SearchName");
    me.search(new QueryParser(VERSION,"name",me.analyzer).parse("house107"));
    System.out.println("-----------------");
    System.out.println("Search3Beds");
    me.search(new QueryParser(VERSION,"beds",me.analyzer).parse("3"));
    System.out.println("-----------------");
    System.out.println("Search3BedsInRange");
    me.search(new QueryParser(VERSION,"name",me.analyzer).parse("beds:[3 TO 3]"));
   }
}

这个程序的输出是:

SearchByRange
executing query"beds:[3 TO 3]"
Found 2 hits.
1. house103, beds:3
2. house107, beds:3
-----------------
SearchName
executing query"name:house107"
Found 1 hits.
1. house107, beds:3
-----------------
Search3Beds
executing query"beds:3"
Found 0 hits.
-----------------
Search3BedsInRange
executing query"beds:[3 TO 3]"
Found 0 hits.

【问题讨论】:

    标签: search lucene numeric


    【解决方案1】:

    你需要做的是写你自己的QueryParser:

    public class CustomQueryParser extends QueryParser {
    
        // ctor omitted 
    
        @Override
        public Query newTermQuery(Term term) {
            if (term.field().equals("beds")) {
               // manually construct and return non-range query for numeric value
            } else {
               return super.newTermQuery(term);
            }
        }
    
        @Override
        public Query newRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) {
            if (field.equals("beds")) {
               // manually construct and return range query for numeric value
            } else {
               return super.newRangeQuery(field, part1, part2, startInclusive, endInclusive);
            }
        }
    }
    

    【讨论】:

    • 有点失望,Lucene 不能解释数字条件。您的解决方案对我帮助最大。我的实现只适用于每个数字字段(不仅适用于床:) if (StringUtils.isNumeric(term.text())) { return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1),Integer.parseInt(part2),第1部分包含,第2部分包含); }
    • 你期待 Lucene 的魔力,记住 Lucene 是一个库而不是一个独立的产品。您想要的功能对 Solr 或 Elasticsearch 有意义。无论如何,这个类所做的就是说“如果字段名称是X,则构造数字查询”。此外,它允许您无缝插入QueryParser 机制:您只需要提供字段名称,而不必自己解析查询。我认为这并不过分。
    • 附注如果你喜欢这个答案,你可能想accept it。这就是这个网站的运作方式。谢谢!
    • 接受了您的回答,但请查看我在底部的帖子。它为所有数字字段描述了一个更通用的解决方案。
    【解决方案2】:

    您需要使用 NumericRangeQuery 对数字字段执行搜索。

    here的答案可以给你一些见解。

    here 的回答也说

    对于数值(长整数、日期、浮点数等),您需要 NumericRangeQuery。否则 Lucene 不知道你想如何定义相似度。

    【讨论】:

      【解决方案3】:

      您似乎总是必须将 NumericRangeQuery 用于数值条件。 (感谢 Mindas)所以他建议我创建自己的更智能的 QueryParser。 使用 Apache commons-lang 函数 StringUtils.isNumeric() 我可以创建一个更通用的 QueryParser:

      public class IntelligentQueryParser extends QueryParser {
          // take over super constructors
      @Override
      protected org.apache.lucene.search.Query newRangeQuery(String field,
              String part1, String part2, boolean part1Inclusive, boolean part2Inclusive) {
          if(StringUtils.isNumeric(part1))
          {
              return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1),Integer.parseInt(part2),part1Inclusive,part2Inclusive);
          }
          return super.newRangeQuery(field, part1, part2, part1Inclusive, part2Inclusive);
      }
      
      @Override
      protected org.apache.lucene.search.Query newTermQuery(
              org.apache.lucene.index.Term term) {
          if(StringUtils.isNumeric(term.text()))
          {
              return NumericRangeQuery.newIntRange(term.field(), Integer.parseInt(term.text()),Integer.parseInt(term.text()),true,true);
          }
          return super.newTermQuery(term);
      }
      }
      

      只是想分享这个。

      【讨论】:

        猜你喜欢
        • 2012-03-13
        • 1970-01-01
        • 1970-01-01
        • 2014-06-09
        • 1970-01-01
        • 2019-06-11
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        相关资源
        最近更新 更多