Lucene增强功能:Payload的应用



Lucene增强功能:Payload的应用
可以在文档中,对给定词出现在文档的出现的权重信息(egg在文档1与文档中,以foods来衡量,文档1更相关),可以在索引之前处理一下,为egg增加payload信息,例如:
  1. 文档1:egg|0.984 tomato potato bread  
  2. 文档2:egg|0.356 book potato bread  
然后再进行索引,通过Lucene提供的PayloadTermQuery就能够分辨出上述egg这个Term的不同。在Lucene中,实际上是将我们存储的Payload数据,如上述“|”分隔后面的数字,乘到了tf上,然后在进行权重的计算。
下面,我们再看一下,增加一个Field来存储Payload数据,而源文档不需要进行修改,或者,我们可以在索引之前对文档进行一个处理,例如分类,通过分类可以给不同的文档所属类别的不同程度,计算一个Payload数值。
为了能够使用存储的Payload数据信息,结合上面提出的实例,我们需要按照如下步骤去做:

第一,待索引数据处理

例如,增加category这个Field存储类别信息,content这个Field存储上面的内容:
  1. 文档1:  
  2. new Field("category", "foods|0.984 shopping|0.503", Field.Store.YES, Field.Index.ANALYZED)  
  3. new Field("content", "egg tomato potato bread", Field.Store.YES, Field.Index.ANALYZED)  
  4. 文档2:  
  5. new Field("category", "foods|0.356 shopping|0.791", Field.Store.YES, Field.Index.ANALYZED)  
  6. new Field("content", "egg book potato bread", Field.Store.YES, Field.Index.ANALYZED)  

第二,实现解析Payload数据的Analyzer

由于Payload信息存储在category这个Field中,多个类别之间使用空格分隔,每个类别内容是以“|”分隔的,所以我们的Analyzer就要能够解析它。Lucene提供了DelimitedPayloadTokenFilter,能够处理具有分隔符的情况。我们的实现如下所示:
  1. public class PayloadAnalyzer extends Analyzer {  
  2.     private PayloadEncoder encoder;  
  3.   
  4.     PayloadAnalyzer(PayloadEncoder encoder) {  
  5.         this.encoder = encoder;  
  6.     }  
  7.   
  8.     @SuppressWarnings("deprecation")  
  9.     public TokenStream tokenStream(String fieldName, Reader reader) {  
  10.         TokenStream result = new WhitespaceTokenizer(reader); // 用来解析空格分隔的各个类别  
  11.         result = new DelimitedPayloadTokenFilter(result, '|', encoder); // 在上面分词的基础上,在进行Payload数据解析  
  12.         return result;  
  13.     }  
  14. }  

第三, 实现Similarity计算得分

Lucene中Similarity类中提供了scorePayload方法,用于计算Payload值来对文档贡献得分,我们重写了该方法,实现如下所示:
  1. public class PayloadSimilarity extends DefaultSimilarity {  
  2.     private static final long serialVersionUID = 1L;  
  3.     @Override  
  4.     public float scorePayload(int docId, String fieldName, int start, int end,  
  5.             byte[] payload, int offset, int length) {  
  6.         return PayloadHelper.decodeFloat(payload, offset);  
  7.     }  
  8. }  

第四,创建索引

在创建索引的时候,需要使用到我们上面实现的Analyzer和Similarity,代码如下所示:
  1.     private IndexWriter indexWriter = null;  
  2.     private final Analyzer analyzer = new PayloadAnalyzer(new FloatEncoder()); // 使用PayloadAnalyzer,并指定Encoder  
  3.     private final Similarity similarity = new PayloadSimilarity(); // 实例化一个PayloadSimilarity  
  4.     private IndexWriterConfig config = null;  
  5.       
  6.     public PayloadIndexing(String indexPath) throws CorruptIndexException, LockObtainFailedException, IOException {  
  7.         File indexFile = new File(indexPath);  
  8.         config = new IndexWriterConfig(Version.LUCENE_31, analyzer);  
  9.         config.setOpenMode(OpenMode.CREATE).setSimilarity(similarity); // 设置计算得分的Similarity  
  10.         indexWriter = new IndexWriter(FSDirectory.open(indexFile), config);  
  11.     } 

第五,查询

查询的时候,我们可以构造PayloadTermQuery来进行查询
  1.     private IndexReader indexReader;  
  2.     private IndexSearcher searcher;  
  3.       
  4.     public PayloadSearching(String indexPath) throws CorruptIndexException, IOException {  
  5.         indexReader = IndexReader.open(NIOFSDirectory.open(new File(indexPath)), true);  
  6.         searcher = new IndexSearcher(indexReader);  
  7.         searcher.setSimilarity(new PayloadSimilarity()); // 设置自定义的PayloadSimilarity  
  8.     }  
  9.       
  10.     public ScoreDoc[] search(String qsr) throws ParseException, IOException {  
  11.         int hitsPerPage = 10;  
  12.         BooleanQuery bq = new BooleanQuery();  
  13.         for(String q : qsr.split(" ")) {  
  14.             bq.add(createPayloadTermQuery(q), Occur.MUST);  
  15.         }  
  16.         TopScoreDocCollector collector = TopScoreDocCollector.create(5 * hitsPerPage, true);  
  17.         searcher.search(bq, collector);  
  18.         ScoreDoc[] hits = collector.topDocs().scoreDocs;  
  19.         for (int i = 0; i < hits.length; i++) {  
  20.             int docId = hits[i].doc; // 文档编号  
  21.             Explanation  explanation  = searcher.explain(bq, docId);  
  22.             System.out.println(explanation.toString());  
  23.         }  
  24.         return hits;  
  25.     }  
  26.       
  27.     public void display(ScoreDoc[] hits, int start, int end) throws CorruptIndexException, IOException {  
  28.         end = Math.min(hits.length, end);  
  29.         for (int i = start; i < end; i++) {  
  30.             Document doc = searcher.doc(hits[i].doc);  
  31.             int docId = hits[i].doc; // 文档编号  
  32.             float score = hits[i].score; // 文档得分  
  33.             System.out.println(docId + "\t" + score + "\t" + doc + "\t");  
  34.         }  
  35.     }  
  36.       
  37.     public void close() throws IOException {  
  38.         searcher.close();  
  39.         indexReader.close();  
  40.     }  
  41.       
  42.     private PayloadTermQuery createPayloadTermQuery(String item) {  
  43.         PayloadTermQuery ptq = null;  
  44.         if(item.indexOf("^")!=-1) {  
  45.             String[] a = item.split("\\^");  
  46.             String field = a[0].split(":")[0];  
  47.             String token = a[0].split(":")[1];  
  48.             ptq = new PayloadTermQuery(new Term(field, token), new AveragePayloadFunction());  
  49.             ptq.setBoost(Float.parseFloat(a[1].trim()));  
  50.         } else {  
  51.             String field = item.split(":")[0];  
  52.             String token = item.split(":")[1];  
  53.             ptq = new PayloadTermQuery(new Term(field, token), new AveragePayloadFunction());  
  54.         }  
  55.         return ptq;  
  56.     }  
  57.       
  58.     public static void main(String[] args) throws ParseException, IOException {  
  59.         int start = 0, end = 10;      
  60. //      String queries = "category:foods^123.0 content:bread^987.0";  
  61.         String queries = "category:foods content:egg";  
  62.         PayloadSearching payloadSearcher = new PayloadSearching("E:\\index");  
  63.         payloadSearcher.display(payloadSearcher.search(queries), start, end);  
  64.         payloadSearcher.close();  
  65.     }  
我们可以看到,除了在计算category权重的时候,tf上乘了一个Payload值以外,其他的都相同,也就是说,我们预期使用的Payload为文档(ID=0)贡献了得分,排名靠前了。否则,如果不使用Payload的话,查询结果中两个文档的得分是相同的(可以模拟设置他们的Payload值相同,测试一下看看)
Please read full article from Lucene增强功能:Payload的应用

No comments:

Post a Comment

Labels

Algorithm (219) Lucene (130) LeetCode (97) Database (36) Data Structure (33) text mining (28) Solr (27) java (27) Mathematical Algorithm (26) Difficult Algorithm (25) Logic Thinking (23) Puzzles (23) Bit Algorithms (22) Math (21) List (20) Dynamic Programming (19) Linux (19) Tree (18) Machine Learning (15) EPI (11) Queue (11) Smart Algorithm (11) Operating System (9) Java Basic (8) Recursive Algorithm (8) Stack (8) Eclipse (7) Scala (7) Tika (7) J2EE (6) Monitoring (6) Trie (6) Concurrency (5) Geometry Algorithm (5) Greedy Algorithm (5) Mahout (5) MySQL (5) xpost (5) C (4) Interview (4) Vi (4) regular expression (4) to-do (4) C++ (3) Chrome (3) Divide and Conquer (3) Graph Algorithm (3) Permutation (3) Powershell (3) Random (3) Segment Tree (3) UIMA (3) Union-Find (3) Video (3) Virtualization (3) Windows (3) XML (3) Advanced Data Structure (2) Android (2) Bash (2) Classic Algorithm (2) Debugging (2) Design Pattern (2) Google (2) Hadoop (2) Java Collections (2) Markov Chains (2) Probabilities (2) Shell (2) Site (2) Web Development (2) Workplace (2) angularjs (2) .Net (1) Amazon Interview (1) Android Studio (1) Array (1) Boilerpipe (1) Book Notes (1) ChromeOS (1) Chromebook (1) Codility (1) Desgin (1) Design (1) Divide and Conqure (1) GAE (1) Google Interview (1) Great Stuff (1) Hash (1) High Tech Companies (1) Improving (1) LifeTips (1) Maven (1) Network (1) Performance (1) Programming (1) Resources (1) Sampling (1) Sed (1) Smart Thinking (1) Sort (1) Spark (1) Stanford NLP (1) System Design (1) Trove (1) VIP (1) tools (1)

Popular Posts