Lucene5学习之SpanQuery跨度查询

    SpanQuery下的子类有好几个,我就放一篇里集中说说。SpanQuery即跨度查询,首先要理解跨度这个概念,Lucene里跨度是用Spans这个类定义的,源码如下:

 

Java代码  

  1. /** Expert: an enumeration of span matches.  Used to implement span searching. 
  2.  * Each span represents a range of term positions within a document.  Matches 
  3.  * are enumerated in order, by increasing document number, within that by 
  4.  * increasing start position and finally by increasing end position. */  
  5. public abstract class Spans {  
  6.   /** Move to the next match, returning true iff any such exists. */  
  7.   public abstract boolean next() throws IOException;  
  8.   
  9.   /** Skips to the first match beyond the current, whose document number is 
  10.    * greater than or equal to <i>target</i>. 
  11.    * <p>The behavior of this method is <b>undefined</b> when called with 
  12.    * <code> target &le; current</code>, or after the iterator has exhausted. 
  13.    * Both cases may result in unpredicted behavior. 
  14.    * <p>Returns true iff there is such 
  15.    * a match.  <p>Behaves as if written: <pre class="prettyprint"> 
  16.    *   boolean skipTo(int target) { 
  17.    *     do { 
  18.    *       if (!next()) 
  19.    *         return false; 
  20.    *     } while (target > doc()); 
  21.    *     return true; 
  22.    *   } 
  23.    * </pre> 
  24.    * Most implementations are considerably more efficient than that. 
  25.    */  
  26.   public abstract boolean skipTo(int target) throws IOException;  
  27.   
  28.   /** Returns the document number of the current match.  Initially invalid. */  
  29.   public abstract int doc();  
  30.   
  31.   /** Returns the start position of the current match.  Initially invalid. */  
  32.   public abstract int start();  
  33.   
  34.   /** Returns the end position of the current match.  Initially invalid. */  
  35.   public abstract int end();  
  36.     
  37.   /** 
  38.    * Returns the payload data for the current span. 
  39.    * This is invalid until {@link #next()} is called for 
  40.    * the first time. 
  41.    * This method must not be called more than once after each call 
  42.    * of {@link #next()}. However, most payloads are loaded lazily, 
  43.    * so if the payload data for the current position is not needed, 
  44.    * this method may not be called at all for performance reasons. An ordered 
  45.    * SpanQuery does not lazy load, so if you have payloads in your index and 
  46.    * you do not want ordered SpanNearQuerys to collect payloads, you can 
  47.    * disable collection with a constructor option.<br> 
  48.    * <br> 
  49.     * Note that the return type is a collection, thus the ordering should not be relied upon. 
  50.     * <br/> 
  51.    * @lucene.experimental 
  52.    * 
  53.    * @return a List of byte arrays containing the data of this payload, otherwise null if isPayloadAvailable is false 
  54.    * @throws IOException if there is a low-level I/O error 
  55.     */  
  56.   // TODO: Remove warning after API has been finalized  
  57.   public abstract Collection<byte[]> getPayload() throws IOException;  
  58.   
  59.   /** 
  60.    * Checks if a payload can be loaded at this position. 
  61.    * <p/> 
  62.    * Payloads can only be loaded once per call to 
  63.    * {@link #next()}. 
  64.    * 
  65.    * @return true if there is a payload available at this position that can be loaded 
  66.    */  
  67.   public abstract boolean isPayloadAvailable() throws IOException;  
  68.     
  69.   /** 
  70.    * Returns the estimated cost of this spans. 
  71.    * <p> 
  72.    * This is generally an upper bound of the number of documents this iterator 
  73.    * might match, but may be a rough heuristic, hardcoded value, or otherwise 
  74.    * completely inaccurate. 
  75.    */  
  76.   public abstract long cost();  
  77. }  

    跨度里包含了匹配Term的起始位置和结束位置信息以及跨度价值估算值以及payload信息等等。

 

   首先要说的就是SpanTermQuery,他和TermQuery用法很相似,唯一区别就是SapnTermQuery可以得到Term的span跨度信息,用法如下:

 

Java代码  

  1. package com.yida.framework.lucene5.query;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.document.TextField;  
  10. import org.apache.lucene.index.DirectoryReader;  
  11. import org.apache.lucene.index.IndexReader;  
  12. import org.apache.lucene.index.IndexWriter;  
  13. import org.apache.lucene.index.IndexWriterConfig;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  16. import org.apache.lucene.search.AutomatonQuery;  
  17. import org.apache.lucene.search.IndexSearcher;  
  18. import org.apache.lucene.search.MultiTermQuery;  
  19. import org.apache.lucene.search.ScoreDoc;  
  20. import org.apache.lucene.search.TopDocs;  
  21. import org.apache.lucene.search.spans.SpanQuery;  
  22. import org.apache.lucene.search.spans.SpanTermQuery;  
  23. import org.apache.lucene.store.Directory;  
  24. import org.apache.lucene.store.RAMDirectory;  
  25. import org.apache.lucene.util.automaton.Automata;  
  26. import org.apache.lucene.util.automaton.Automaton;  
  27. /** 
  28.  * SpanTermQuery用法测试 
  29.  * @author Lanxiaowei 
  30.  * 
  31.  */  
  32. public class SpanTermQueryTest {  
  33.     public static void main(String[] args) throws IOException {  
  34.         Directory dir = new RAMDirectory();  
  35.         Analyzer analyzer = new StandardAnalyzer();  
  36.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  37.         iwc.setOpenMode(OpenMode.CREATE);  
  38.         IndexWriter writer = new IndexWriter(dir, iwc);  
  39.   
  40.         Document doc = new Document();  
  41.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  42.         writer.addDocument(doc);  
  43.           
  44.         doc = new Document();  
  45.         doc.add(new TextField("text", "the quick red fox jumps over the sleepy cat", Field.Store.YES));  
  46.         writer.addDocument(doc);  
  47.           
  48.         doc = new Document();  
  49.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  50.         writer.addDocument(doc);  
  51.         writer.close();  
  52.   
  53.         IndexReader reader = DirectoryReader.open(dir);  
  54.         IndexSearcher searcher = new IndexSearcher(reader);  
  55.           
  56.         String queryString = "red";  
  57.         SpanQuery query = new SpanTermQuery(new Term("text",queryString));  
  58.           
  59.         TopDocs results = searcher.search(query, null, 100);  
  60.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  61.           
  62.         for (int i = 0; i < scoreDocs.length; ++i) {  
  63.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  64.             int docID = scoreDocs[i].doc;  
  65.             Document document = searcher.doc(docID);  
  66.             String path = document.get("text");  
  67.             System.out.println("text:" + path);  
  68.         }  
  69.     }  
  70. }  

   SpanNearQuery:用来匹配两个Term之间的跨度的,即一个Term经过几个跨度可以到达另一个Term,slop为跨度因子,用来限制两个Term之间的最大跨度,不可能一个Term和另一个Term之间要经过十万八千个跨度才到达也算两者相近,这不符合常理。所以有个slop因子进行限制。还有一个inOrder参数要引起注意,它用来设置是否允许进行倒序跨度,什么意思?即TermA到TermB不一定是从左到右去匹配也可以从右到左,而从右到左就是倒序,inOrder为true即表示order(顺序)很重要不能倒序去匹配必须正向去匹配,false则反之。注意停用词不在slop统计范围内

    Slop的理解很重要:

    在默认情况下slop的值是0, 就相当于TermQuery的精确匹配, 通过设置slop参数(比如"one five"匹配"one two three four five"就需要slop=3,如果slop=2就无法得到结果。这里我们可以认为slope是单词移动得次数,可以左移或者右移。这里特别提 醒,PhraseQuery不保证前后单词的次序,在上面的例子中,"two one"就需要2个slop,也就是认为one 向左边移动2位, 就是能够匹配的”one two”如果是“five three one” 就需要slope=6才能匹配。

 

还有一个collectPayloads参数表示是否收集payload信息,关于payload后面再单独说。

 

    SpanNearQuery的构造函数如下:

 

Java代码  

  1. public SpanNearQuery(SpanQuery[] clauses, int slop, boolean inOrder, boolean collectPayloads) {  
  2.   
  3.     // copy clauses array into an ArrayList  
  4.     this.clauses = new ArrayList<>(clauses.length);  
  5.     for (int i = 0; i < clauses.length; i++) {  
  6.       SpanQuery clause = clauses[i];  
  7.       if (field == null) {                               // check field  
  8.         field = clause.getField();  
  9.       } else if (clause.getField() != null && !clause.getField().equals(field)) {  
  10.         throw new IllegalArgumentException("Clauses must have same field.");  
  11.       }  
  12.       this.clauses.add(clause);  
  13.     }  
  14.     this.collectPayloads = collectPayloads;  
  15.     this.slop = slop;  
  16.     this.inOrder = inOrder;  
  17.   }  

   SpanNearQuery使用示例:

 

 

Java代码  

  1. /** 
  2.  * SpanNearQuery测试 
  3.  * @author Lanxiaowei 
  4.  * 
  5.  */  
  6. public class SpanNearQueryTest {  
  7.     public static void main(String[] args) throws IOException {  
  8.         Directory dir = new RAMDirectory();  
  9.         Analyzer analyzer = new StandardAnalyzer();  
  10.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  11.         iwc.setOpenMode(OpenMode.CREATE);  
  12.         IndexWriter writer = new IndexWriter(dir, iwc);  
  13.   
  14.         Document doc = new Document();  
  15.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  16.         writer.addDocument(doc);  
  17.           
  18.         doc = new Document();  
  19.         doc.add(new TextField("text", "the quick red fox jumps over the sleepy cat", Field.Store.YES));  
  20.         writer.addDocument(doc);  
  21.           
  22.         doc = new Document();  
  23.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  24.         writer.addDocument(doc);  
  25.         writer.close();  
  26.   
  27.         IndexReader reader = DirectoryReader.open(dir);  
  28.         IndexSearcher searcher = new IndexSearcher(reader);  
  29.           
  30.         String queryStringStart = "dog";  
  31.         String queryStringEnd = "quick";  
  32.         SpanQuery queryStart = new SpanTermQuery(new Term("text",queryStringStart));  
  33.         SpanQuery queryEnd = new SpanTermQuery(new Term("text",queryStringEnd));  
  34.         SpanQuery spanNearQuery = new SpanNearQuery(  
  35.             new SpanQuery[] {queryStart,queryEnd}, 6, false, false);  
  36.           
  37.         TopDocs results = searcher.search(spanNearQuery, null, 100);  
  38.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  39.           
  40.         for (int i = 0; i < scoreDocs.length; ++i) {  
  41.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  42.             int docID = scoreDocs[i].doc;  
  43.             Document document = searcher.doc(docID);  
  44.             String path = document.get("text");  
  45.             System.out.println("text:" + path);  
  46.         }  
  47.     }  
  48. }  

   示例中dog要到达quick需要经过6个跨度,需要从右至左倒序匹配,所以inOrder设置为false,如果设置为true会导致查询不出来数据。

 

   SpanNotQuery:使用场景是当使用SpanNearQuery时,如果两个Term从TermA到TermB有多种情况,即可能出现TermA或者TermB在索引中重复出现,则可能有多种情况,SpanNotQuery就是用来限制TermA和TermB之间不存在TermC,从而排除一些情况,实现更精确的控制。默认SpanNotQuery的构造函数是这样的:

 

Java代码  

  1. /** Construct a SpanNotQuery matching spans from <code>include</code> which 
  2.    * have no overlap with spans from <code>exclude</code>.*/  
  3.   public SpanNotQuery(SpanQuery include, SpanQuery exclude) {  
  4.      this(include, exclude, 0, 0);  
  5.   }  

 显然这里的第一个参数include应该是SpanNearQuery,第二个参数就是用来做排除的。

 

   SpanNotQuery另一个重载构造函数如下:

 

Java代码  

  1. /** Construct a SpanNotQuery matching spans from <code>include</code> which 
  2.    * have no overlap with spans from <code>exclude</code> within  
  3.    * <code>dist</code> tokens of <code>include</code>. */  
  4.   public SpanNotQuery(SpanQuery include, SpanQuery exclude, int dist) {  
  5.      this(include, exclude, dist, dist);  
  6.   }  
  7.     

 它多加了一个dist参数,官方的解释是:Construct a SpanNotQuery matching spans from include which have no overlap with spans from exclude within dist tokens of include. 说白了就是,使用exclude限制以后匹配到以后,TermA和TermB之间间隔的字符长度做个限制,这就是dist的作用。

 

SpanNotQuery还有一个更复杂的构造函数重载:

 

Java代码  

  1. /** Construct a SpanNotQuery matching spans from <code>include</code> which 
  2.    * have no overlap with spans from <code>exclude</code> within  
  3.    * <code>pre</code> tokens before or <code>post</code> tokens of <code>include</code>. */  
  4.   public SpanNotQuery(SpanQuery include, SpanQuery exclude, int pre, int post) {  
  5.     this.include = include;  
  6.     this.exclude = exclude;  
  7.     this.pre = (pre >=0) ? pre : 0;  
  8.     this.post = (post >= 0) ? post : 0;  
  9.   
  10.     if (include.getField() != null && exclude.getField() != null && !include.getField().equals(exclude.getField()))  
  11.       throw new IllegalArgumentException("Clauses must have same field.");  
  12.   }  

 最后一个post参数其实就是dist,pre参数就是限制exclude Term前面有几个字符。这样解释太抽象,用示例代码来说明吧:

 

 

Java代码  

  1. package com.yida.framework.lucene5.query;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.document.TextField;  
  10. import org.apache.lucene.index.DirectoryReader;  
  11. import org.apache.lucene.index.IndexReader;  
  12. import org.apache.lucene.index.IndexWriter;  
  13. import org.apache.lucene.index.IndexWriterConfig;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  16. import org.apache.lucene.search.IndexSearcher;  
  17. import org.apache.lucene.search.ScoreDoc;  
  18. import org.apache.lucene.search.TopDocs;  
  19. import org.apache.lucene.search.spans.SpanNearQuery;  
  20. import org.apache.lucene.search.spans.SpanNotQuery;  
  21. import org.apache.lucene.search.spans.SpanQuery;  
  22. import org.apache.lucene.search.spans.SpanTermQuery;  
  23. import org.apache.lucene.store.Directory;  
  24. import org.apache.lucene.store.RAMDirectory;  
  25.   
  26. /** 
  27.  * SpanNotQuery测试 
  28.  * @author Lanxiaowei 
  29.  * 
  30.  */  
  31. public class SpanNotQueryTest {  
  32.     public static void main(String[] args) throws IOException {  
  33.         Directory dir = new RAMDirectory();  
  34.         Analyzer analyzer = new StandardAnalyzer();  
  35.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  36.         iwc.setOpenMode(OpenMode.CREATE);  
  37.         IndexWriter writer = new IndexWriter(dir, iwc);  
  38.   
  39.         Document doc = new Document();  
  40.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  41.         writer.addDocument(doc);  
  42.           
  43.         doc = new Document();  
  44.         doc.add(new TextField("text", "the quick red fox jumps over the sleepy cat", Field.Store.YES));  
  45.         writer.addDocument(doc);  
  46.           
  47.         doc = new Document();  
  48.         doc.add(new TextField("text", "the quick brown fox quick gox jumps over the lazy dog", Field.Store.YES));  
  49.         writer.addDocument(doc);  
  50.           
  51.         doc = new Document();  
  52.         doc.add(new TextField("text", "the quick brown adult slave nice fox winde felt testcase gox quick jumps over the lazy dog", Field.Store.YES));  
  53.         writer.addDocument(doc);  
  54.           
  55.         doc = new Document();  
  56.         doc.add(new TextField("text", "the quick brown fox quick jumps over the lazy dog", Field.Store.YES));  
  57.         writer.addDocument(doc);  
  58.         writer.close();  
  59.   
  60.         IndexReader reader = DirectoryReader.open(dir);  
  61.         IndexSearcher searcher = new IndexSearcher(reader);  
  62.           
  63.         String queryStringStart = "dog";  
  64.         String queryStringEnd = "quick";  
  65.         String excludeString = "fox";  
  66.         SpanQuery queryStart = new SpanTermQuery(new Term("text",queryStringStart));  
  67.         SpanQuery queryEnd = new SpanTermQuery(new Term("text",queryStringEnd));  
  68.         SpanQuery excludeQuery = new SpanTermQuery(new Term("text",excludeString));  
  69.         SpanQuery spanNearQuery = new SpanNearQuery(  
  70.             new SpanQuery[] {queryStart,queryEnd}, 12, false, false);  
  71.           
  72.         SpanNotQuery spanNotQuery = new SpanNotQuery(spanNearQuery, excludeQuery, 4,3);  
  73.         TopDocs results = searcher.search(spanNotQuery, null, 100);  
  74.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  75.           
  76.         for (int i = 0; i < scoreDocs.length; ++i) {  
  77.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  78.             int docID = scoreDocs[i].doc;  
  79.             Document document = searcher.doc(docID);  
  80.             String path = document.get("text");  
  81.             System.out.println("text:" + path);  
  82.         }  
  83.     }  
  84. }  

   示例代码意思就是查询dog和quick之间没有fox的索引文档,自己运行示例代码参悟吧。

 

   SpanOrQuery顾名思义就是把多个Span'Query用or连接起来,其实你也可以用BooleanQuery来代替SpanOrQuery,但SpanOrQuery会返回额外的Span跨度信息,它的构造函数如下:

 

Java代码  

  1. SpanOrQuery(SpanQuery... clauses)   

    接收多个SpanQuery对象并用or连接起来,下面是SpanOrQuery示例代码:

 

   

Java代码  

  1. package com.yida.framework.lucene5.query;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.document.TextField;  
  10. import org.apache.lucene.index.DirectoryReader;  
  11. import org.apache.lucene.index.IndexReader;  
  12. import org.apache.lucene.index.IndexWriter;  
  13. import org.apache.lucene.index.IndexWriterConfig;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  16. import org.apache.lucene.search.IndexSearcher;  
  17. import org.apache.lucene.search.ScoreDoc;  
  18. import org.apache.lucene.search.TopDocs;  
  19. import org.apache.lucene.search.spans.SpanNearQuery;  
  20. import org.apache.lucene.search.spans.SpanNotQuery;  
  21. import org.apache.lucene.search.spans.SpanOrQuery;  
  22. import org.apache.lucene.search.spans.SpanQuery;  
  23. import org.apache.lucene.search.spans.SpanTermQuery;  
  24. import org.apache.lucene.store.Directory;  
  25. import org.apache.lucene.store.RAMDirectory;  
  26.   
  27. /** 
  28.  * SpanOrQuery测试 
  29.  * @author Lanxiaowei 
  30.  * 
  31.  */  
  32. public class SpanOrQueryTest {  
  33.     public static void main(String[] args) throws IOException {  
  34.         Directory dir = new RAMDirectory();  
  35.         Analyzer analyzer = new StandardAnalyzer();  
  36.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  37.         iwc.setOpenMode(OpenMode.CREATE);  
  38.         IndexWriter writer = new IndexWriter(dir, iwc);  
  39.   
  40.         Document doc = new Document();  
  41.         doc.add(new TextField("text", "the quick brown fox jumps over the lazy dog", Field.Store.YES));  
  42.         writer.addDocument(doc);  
  43.           
  44.         doc = new Document();  
  45.         doc.add(new TextField("text", "the quick red fox jumps over the sleepy cat", Field.Store.YES));  
  46.         writer.addDocument(doc);  
  47.           
  48.         doc = new Document();  
  49.         doc.add(new TextField("text", "the quick brown fox quick gox jumps over the lazy dog", Field.Store.YES));  
  50.         writer.addDocument(doc);  
  51.           
  52.         doc = new Document();  
  53.         doc.add(new TextField("text", "the quick brown adult slave nice fox winde felt testcase gox quick jumps over the lazy dog", Field.Store.YES));  
  54.         writer.addDocument(doc);  
  55.           
  56.         doc = new Document();  
  57.         doc.add(new TextField("text", "the quick brown adult sick slave nice fox winde felt testcase fox quick jumps over the lazy dog", Field.Store.YES));  
  58.         writer.addDocument(doc);  
  59.           
  60.         doc = new Document();  
  61.         doc.add(new TextField("text", "the quick brown fox quick jumps over the lazy dog", Field.Store.YES));  
  62.         writer.addDocument(doc);  
  63.         writer.close();  
  64.   
  65.         IndexReader reader = DirectoryReader.open(dir);  
  66.         IndexSearcher searcher = new IndexSearcher(reader);  
  67.           
  68.         String queryStringStart = "dog";  
  69.         String queryStringEnd = "quick";  
  70.         String excludeString = "fox";  
  71.         String termString = "sick";  
  72.         SpanQuery queryStart = new SpanTermQuery(new Term("text",queryStringStart));  
  73.         SpanQuery queryEnd = new SpanTermQuery(new Term("text",queryStringEnd));  
  74.         SpanQuery excludeQuery = new SpanTermQuery(new Term("text",excludeString));  
  75.         SpanQuery spanNearQuery = new SpanNearQuery(  
  76.             new SpanQuery[] {queryStart,queryEnd}, 12, false, false);  
  77.           
  78.         SpanNotQuery spanNotQuery = new SpanNotQuery(spanNearQuery, excludeQuery, 4,3);  
  79.           
  80.         SpanQuery spanTermQuery = new SpanTermQuery(new Term("text",termString));  
  81.           
  82.         SpanOrQuery spanOrQuery = new SpanOrQuery(spanNotQuery,spanTermQuery);  
  83.           
  84.         TopDocs results = searcher.search(spanOrQuery, null, 100);  
  85.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  86.           
  87.         for (int i = 0; i < scoreDocs.length; ++i) {  
  88.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  89.             int docID = scoreDocs[i].doc;  
  90.             Document document = searcher.doc(docID);  
  91.             String path = document.get("text");  
  92.             System.out.println("text:" + path);  
  93.         }  
  94.     }  
  95. }  

   SpanMultiTermQueryWrapper:就是一个Query转换器,用于把MultiTermQuery包装转换成SpanQuery的,具体使用示例,我贴下官方API里提供的示例代码吧:

 

 

Java代码  

  1. WildcardQuery wildcard = new WildcardQuery(new Term("field", "bro?n"));  
  2.  SpanQuery spanWildcard = new SpanMultiTermQueryWrapper<WildcardQuery>(wildcard);  

 SpanPositionRangeQuery:这个query是用来限制匹配的情况是否分布在(start,end)这个区间内,区间索引从零开始计算,拿示例代码说话,

 

 

Java代码  

  1. package com.yida.framework.lucene5.query;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.document.TextField;  
  10. import org.apache.lucene.index.DirectoryReader;  
  11. import org.apache.lucene.index.IndexReader;  
  12. import org.apache.lucene.index.IndexWriter;  
  13. import org.apache.lucene.index.IndexWriterConfig;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  16. import org.apache.lucene.search.FuzzyQuery;  
  17. import org.apache.lucene.search.IndexSearcher;  
  18. import org.apache.lucene.search.ScoreDoc;  
  19. import org.apache.lucene.search.TopDocs;  
  20. import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper;  
  21. import org.apache.lucene.search.spans.SpanNearQuery;  
  22. import org.apache.lucene.search.spans.SpanNotQuery;  
  23. import org.apache.lucene.search.spans.SpanPositionRangeQuery;  
  24. import org.apache.lucene.search.spans.SpanQuery;  
  25. import org.apache.lucene.search.spans.SpanTermQuery;  
  26. import org.apache.lucene.store.Directory;  
  27. import org.apache.lucene.store.RAMDirectory;  
  28.   
  29. /** 
  30.  * SpanPositionRangeQuery测试 
  31.  * @author Lanxiaowei 
  32.  * 
  33.  */  
  34. public class SpanPositionRangeQueryTest {  
  35.     public static void main(String[] args) throws IOException {  
  36.         Directory dir = new RAMDirectory();  
  37.         Analyzer analyzer = new StandardAnalyzer();  
  38.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  39.         iwc.setOpenMode(OpenMode.CREATE);  
  40.         IndexWriter writer = new IndexWriter(dir, iwc);  
  41.   
  42.         Document doc = new Document();  
  43.         doc.add(new TextField("text", "quick brown fox", Field.Store.YES));  
  44.         writer.addDocument(doc);  
  45.           
  46.         doc = new Document();  
  47.         doc.add(new TextField("text", "jumps over lazy broun dog", Field.Store.YES));  
  48.         writer.addDocument(doc);  
  49.           
  50.         doc = new Document();  
  51.         doc.add(new TextField("text", "jumps over extremely very lazy broxn dog", Field.Store.YES));  
  52.         writer.addDocument(doc);  
  53.           
  54.           
  55.         writer.close();  
  56.   
  57.         IndexReader reader = DirectoryReader.open(dir);  
  58.         IndexSearcher searcher = new IndexSearcher(reader);  
  59.           
  60.         FuzzyQuery fq = new FuzzyQuery(new Term("text", "broan"));  
  61.         SpanQuery sfq = new SpanMultiTermQueryWrapper<FuzzyQuery>(fq);  
  62.           
  63.         SpanPositionRangeQuery spanPositionRangeQuery = new SpanPositionRangeQuery(sfq, 3, 5);  
  64.           
  65.         TopDocs results = searcher.search(spanPositionRangeQuery, null, 100);  
  66.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  67.           
  68.         for (int i = 0; i < scoreDocs.length; ++i) {  
  69.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  70.             int docID = scoreDocs[i].doc;  
  71.             Document document = searcher.doc(docID);  
  72.             String path = document.get("text");  
  73.             System.out.println("text:" + path);  
  74.         }  
  75.     }  
  76. }  

 稍微解释下上面的代码,首先呢,FuzzyQuery fq = new FuzzyQuery(new Term("text", "broan"));用来查询包含跟单词broan相似字符的索引文档,显然第一个索引文档不符合排除了一个,然后呢,我们new了一个SpanQuery包装器Wrapper,把FuzzyQuery转换成了SpanQuery,然后使用SpanPositionRangeQuery对匹配到的2种情况的落放的位置进行限制即跟broan相似的单词必须分布在(3,5)这个区间内,显然第3个索引文档是分布在(3,6)这个区间内,所以第3个索引文档被排除了,最后只返回第2个索引文档。

 

    SpanPositionRangeQuery还有个子类SpanFirstQuery,其实SpanFirstQuery只不过是把SpanPositionRangeQuery构造函数里的start参数值设置为0,仅此而已,所以不用多说,你也懂的,它的构造函数如下:

Java代码  

  1. SpanFirstQuery(SpanQuery match, int end)   
  2. Construct a SpanFirstQuery matching spans in match whose end position is less than or equal to end.  

 这也就是为什么只有一个end,没有start,因为start默认为零,看源码:


 SpanFirstQuery示例我就不提供了,略过。

   最后一个要说的就是FieldMaskingSpanQuery,它用于在多个域之间查询,即把另一个域看作某个域,从而看起来就像在同一个域里查询,因为Lucene默认某个条件只能作用在单个域上,不支持跨域查询只能在同一个域里查询,所以有了FieldMaskingSpanQuery,,下面是示例代码:

Java代码  

  1. package com.yida.framework.lucene5.query;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.Analyzer;  
  6. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.index.DirectoryReader;  
  10. import org.apache.lucene.index.IndexReader;  
  11. import org.apache.lucene.index.IndexWriter;  
  12. import org.apache.lucene.index.IndexWriterConfig;  
  13. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.search.IndexSearcher;  
  16. import org.apache.lucene.search.Query;  
  17. import org.apache.lucene.search.ScoreDoc;  
  18. import org.apache.lucene.search.TopDocs;  
  19. import org.apache.lucene.search.spans.FieldMaskingSpanQuery;  
  20. import org.apache.lucene.search.spans.SpanNearQuery;  
  21. import org.apache.lucene.search.spans.SpanQuery;  
  22. import org.apache.lucene.search.spans.SpanTermQuery;  
  23. import org.apache.lucene.store.Directory;  
  24. import org.apache.lucene.store.RAMDirectory;  
  25.   
  26. /** 
  27.  * FieldMaskingSpanQuery测试 
  28.  * @author Lanxiaowei 
  29.  * 
  30.  */  
  31. public class FieldMaskingSpanQueryTest {  
  32.     public static void main(String[] args) throws IOException {  
  33.         Directory dir = new RAMDirectory();  
  34.         Analyzer analyzer = new StandardAnalyzer();  
  35.         IndexWriterConfig iwc = new IndexWriterConfig(analyzer);  
  36.         iwc.setOpenMode(OpenMode.CREATE);  
  37.         IndexWriter writer = new IndexWriter(dir, iwc);  
  38.   
  39.         Document doc = new Document();  
  40.   
  41.         doc.add(new Field("teacherid", "1", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  42.   
  43.         doc.add(new Field("studentfirstname", "james", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  44.           
  45.         doc.add(new Field("studentsurname", "jones", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  46.   
  47.         writer.addDocument(doc);  
  48.           
  49.           
  50.         //teacher2  
  51.         doc = new Document();  
  52.   
  53.         doc.add(new Field("teacherid", "2", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  54.   
  55.         doc.add(new Field("studentfirstname", "james", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  56.   
  57.         doc.add(new Field("studentsurname", "smith", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  58.   
  59.         doc.add(new Field("studentfirstname", "sally", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  60.   
  61.         doc.add(new Field("studentsurname", "jones", Field.Store.YES, Field.Index.NOT_ANALYZED));  
  62.   
  63.         writer.addDocument(doc);  
  64.           
  65.         writer.close();  
  66.   
  67.         IndexReader reader = DirectoryReader.open(dir);  
  68.         IndexSearcher searcher = new IndexSearcher(reader);  
  69.           
  70.         SpanQuery q1  = new SpanTermQuery(new Term("studentfirstname", "james"));  
  71.         SpanQuery q2  = new SpanTermQuery(new Term("studentsurname", "jones"));  
  72.           
  73.         SpanQuery q2m = new FieldMaskingSpanQuery(q2, "studentfirstname");  
  74.   
  75.         Query query = new SpanNearQuery(new SpanQuery[]{q1, q2m}, -1, false);  
  76.         TopDocs results = searcher.search(query, null, 100);  
  77.         ScoreDoc[] scoreDocs = results.scoreDocs;  
  78.           
  79.         for (int i = 0; i < scoreDocs.length; ++i) {  
  80.             //System.out.println(searcher.explain(query, scoreDocs[i].doc));  
  81.             int docID = scoreDocs[i].doc;  
  82.             Document document = searcher.doc(docID);  
  83.             String teacherid = document.get("teacherid");  
  84.             System.out.println("teacherid:" + teacherid);  
  85.         }  
  86.     }  
  87. }  

   OK,SpanQuery就说这么多,接下来要说的就是PhraseQuery。

 

   如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

转载:http://iamyida.iteye.com/blog/2195761

时间: 2024-10-10 18:59:31

Lucene5学习之SpanQuery跨度查询的相关文章

Lucene5学习之FunctionQuery功能查询

    我猜,大家最大的疑问就是:不是已经有那么多Query实现类吗,为什么又设计一个FunctionQuery,它的设计初衷是什么,或者说它是用来解决什么问题的?我们还是来看看源码里是怎么解释FunctionQuery的:         意思就是基于ValueSource来返回每个文档的评分即valueSourceScore,那ValueSource又是怎么东东?接着看看ValueSource源码里的注释说明:  ValueSource是用来根据指定的IndexReader来实例化Funct

Lucene5学习之PhraseQuery短语查询

    PhraseQuery:短语查询,就是查询文档中是否包含指定的一个Term或多个Term,多个Term之间可以指定间隔即slop参数,官方API解释如图:     使用示例代码,如下:   Java代码   package com.yida.framework.lucene5.query;      import java.io.IOException;      import org.apache.lucene.analysis.Analyzer;   import org.apach

Lucene5学习之多线程创建索引

    昨晚睡觉前把多线程创建索引demo写好了,今天早上7点多就起来,趁着劲头赶紧记录分享一下,这样对那些同样对Lucene感兴趣的童鞋也有所帮助.     我们都知道Lucene的IndexWriter在构造初始化的时候会去获取索引目录的写锁writerLock,加锁的目的就是保证同时只能有一个IndexWriter实例在往索引目录中写数据,具体看截图:  而在多线程环境下,光保证只有IndexWriter实例能得到锁还不行,还必须保证每次只能有一个线程能获取到writerLock,Luce

Lucene5学习之Filter过滤器

  清明3天假,我猜小伙伴们都相约出去玩去了,对于我等屌丝来说,唯有在家写代码打发时间了.其实不是我喜欢宅,只是一个人去哪儿都没有激情,还不如在家安安静静的看看书写写代码来的安逸,对这个看脸的世界就差绝望了,就算代码虐我千万遍,我待代码还是如初恋啊!今天从早上9点起来,就中午做个饭,一坐就是整整10个小时,照着我预想的计划继续记录我的Lucene5学习轨迹,由于Filter体系下子类有点多,还要编写测试demo,所以这篇博客有点姗姗来迟,请大家多多包涵!                    

Lucene5学习之自定义排序

         在Lucene5学习之排序-Sort中,我们已经学习了Sort的用法,已经了解了,Lucene搜索返回的命中结果默认是按照索引文档跟搜索关键字的相关度已经排序的,而相关度又是基于内部的打分机制和索引文档id,内部的打分机制则是根据Term的IDF-TF以及创建索引时Field的boost等决定的,默认是按照得分降序排序,得分相同再按docId升序排序.如果你觉得默认的排序方式满足不了你的需求,你可以设置SortField按照特定的域来排序,特定的域排序其实根据域的type类型去

ASP.NET MVC 5 学习教程:添加查询

原文 ASP.NET MVC 5 学习教程:添加查询 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 通过控制器访问模型的数据 生成的代码详解 使用 SQL Server LocalDB Edit方法和Edit视图详解 添加查询 Entity Framework 数据迁移之添加字段 添加验证 Details 和 Delete 方法详解 在本节中,我们为 Index 方法添加查询功能,使我们能够根据电影的题

Elasticsearch Span Query跨度查询

ES基于Lucene开发,因此也继承了Lucene的一些多样化的查询,比如本篇说的Span Query跨度查询,就是基于Lucene中的SpanTermQuery以及其他的Query封装出的DSL,接下来就看一下这些DSL都如何使用吧! 更多翻译参考:Elasticsearch知识汇总 span_term查询 这个查询如果单独使用,效果跟term查询差不多,但是一般还是用于其他的span查询的子查询. 用法也很简单,只需要指定查询的字段即可: { "span_term" : { &qu

Lucene5学习之分页查询

Java代码   package com.yida.framework.lucene5.core;      import java.io.IOException;   import java.nio.file.Paths;   import java.util.ArrayList;   import java.util.List;      import org.apache.lucene.analysis.standard.StandardAnalyzer;   import org.apa

Lucene5学习之多索引目录查询以及多线程查询

   上一篇中我们使用多线程创建了索引,下面我们来试着采用不把多个索引目录里的数据合并到一个新的索引目录的方式去查询索引数据,当然你也可以合并(合并到一个索引目录查询就很简单了),其实很多情况我们都是不合并到一个索引目录的,那多索引目录该如何查询呢,在Lucene5中使用的MultiReader类,在Lucene4时代,使用的是MultiSearcher类.至于Lucene多线程查询,只需要在构建IndexSearcher对象时传入一个ExecutorService线程池管理对象即可,具体请看下