2014-05-21 3 views
0

이 작은 프로그램을 작성하기 위해 lucene 쿼리 구문이 어떻게 작동하는지 이해하려고합니다. NumericRangeQuery를 사용할 때 원하는 문서를 찾을 수 있지만 검색 조건을 파싱하려고 할 때 동일한 조건을 사용하지만 히트를 찾을 수 없습니다. 차이점은 분석기로 설명 할 수 있지만 숫자 값은 제거하지 않는 StandardAnalyzer가 사용된다는 것을 알고 있습니다.숫자 필드를 사용하는 Lucene 쿼리가 아무 것도 찾지 못했습니다.

누군가 내가 뭘 잘못하고 있다고 말할 수 있습니까? 감사합니다. .

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. 

답변

0

가 작성하는 것입니다 자신의 QueryParser : 당신은 항상 숫자 조건에 대한 NumericRangeQuery를 사용해야처럼

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); 
     } 
    } 
} 
+1

Lucene이 숫자 조건을 해석 할 수는 없지만 실망감은 조금 있습니다. 귀하의 솔루션이 도움이되었습니다. 내 구현은 모든 숫자 필드 (침대뿐만 아니라)에 대해서만 작동합니다. { return NumericRangeQuery.newIntRange (field, part2), part1 포함, part2 포함); } – Conffusion

+0

Lucene에서 마법을 기대합니다. Lucene은 독립형 제품이 아니라 라이브러리입니다. 원하는 기능은 Solr 또는 Elasticsearch에 적합합니다. 어쨌든,이 클래스가하는 일은 "필드 이름이 X이면 숫자 쿼리를 구성하는 것"입니다. 게다가, 그것은 당신이'QueryParser' 메카니즘에 완벽하게 연결될 수 있도록 해줍니다 : 당신은 필드 이름을 제공 할 필요가 있고 쿼리를 직접 파싱 할 필요가 없습니다. 나는 그렇게 많이 생각하지 않는다. – mindas

+0

p.s. 대답을 원한다면 [동의] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)를 원할 수 있습니다. 이것이이 사이트의 작동 방식입니다. 고맙습니다! – mindas

0

당신은 숫자 필드에서 검색을 수행 할 NumericRangeQuery를 사용해야합니다.

대답은 here에 대한 통찰력을 줄 수 있습니다.

또한 대답은 here 당신이 NumericRangeQuery이 필요 숫자 값 (걷고, 날짜, 수레 등)

을 말한다. 그렇지 않으면 Lucene은 당신이 어떻게 유사성을 정의하기를 원하지는 모른다. 당신이해야 할 일은

0

것 같다. (Mindas 덕분에) 그는 내가 더 지능적인 QueryParser를 만들 것을 제안했다. 내가 더 일반적인 QueryParser를 만들 수 있습니다() 아파치 평민 - 랭 기능 StringUtils.isNumeric를 사용 는 :

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); 
} 
} 

그냥이 공유하고 싶었다.

관련 문제