分享

一步一步跟我学习lucene(10)---lucene搜索之联想词提示之suggest原理和应用

 Bladexu的文库 2018-01-10

昨天了解了suggest包中的spell相关的内容,主要是拼写检查和相似度查询提示;

今天准备了解下关于联想词的内容,lucene的联想词是在org.apache.lucene.search.suggest包下边,提供了自动补全或者联想提示功能的支持;

InputIterator说明

InputIterator是一个支持枚举term,weight,payload三元组的供suggester使用的接口,目前仅支持AnalyzingSuggester,FuzzySuggester andAnalyzingInfixSuggester 三种suggester支持payloads;

InputIterator的实现类有以下几种:

BufferedInputIterator:对二进制类型的输入进行轮询;

DocumentInputIterator:从索引中被store的field中轮询;

FileIterator:从文件中每次读出单行的数据轮询,以\t进行间隔(且\t的个数最多为2个);

HighFrequencyIterator:从索引中被store的field轮询,忽略长度小于设定值的文本;

InputIteratorWrapper:遍历BytesRefIterator并且返回的内容不包含payload且weight均为1;

SortedInputIterator:二进制类型的输入轮询且按照指定的comparator算法进行排序;


InputIterator提供的方法如下:


weight():此方法设置某个term的权重,设置的越高suggest的优先级越高;

payload():每个suggestion对应的元数据的二进制表示,我们在传输对象的时候需要转换对象或对象的某个属性为BytesRef类型,相应的suggester调用lookup的时候会返回payloads信息;

hasPayload():判断iterator是否有payloads;

contexts():获取某个term的contexts,用来过滤suggest的内容,如果suggest的列表为空,返回null

hasContexts():获取iterator是否有contexts;

Suggester查询工具Lookup类说明

此类提供了字符串的联想查询功能

Lookup类提供了一个CharSequenceComparator,此comparator主要是用来对CharSequence进行排序,按字符顺序排序;

内置LookupResult,用于返回suggest的结果,同时也是按照CharSequenceComparator进行key的排序;

内置了LookupPriorityQueue,用以存储LookupResult;


LookUp提供的方法

build(Dictionary dict)  : 从指定directory进行build;

load(InputStream input) : 将InputStream转成DataInput并执行load(DataInput)方法;

store(OutputStream output) : 将OutputStream转成DataOutput并执行store(DataOutput)方法;

getCount() : 获取lookup的build的项的数量;

build(InputIterator inputIterator) : 根据指定的InputIterator构建Lookup对象;

lookup(CharSequence key, boolean onlyMorePopular, int num) :根据key查询可能的结果返回值为List<LookupResult>;


Lookup的相关实现如下:

编写自己的suggest模块

注意:在suggest的时候我们需要导入lucene-misc-5.1.0.jar否则系统会提示类SortedMergePolicy没有找到;

首先我们定义自己的实体类:

[java] view plain copy
  1. package com.lucene.suggest;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class Product implements Serializable {  
  6.     private static final long serialVersionUID = 1L;  
  7.     private String name;  
  8.     private String image;  
  9.     private String[] regions;  
  10.     private int numberSold;  
  11.   
  12.     public Product(String name, String image, String[] regions, int numberSold) {  
  13.         this.name = name;  
  14.         this.image = image;  
  15.         this.regions = regions;  
  16.         this.numberSold = numberSold;  
  17.     }  
  18.   
  19.     public String getName() {  
  20.         return name;  
  21.     }  
  22.   
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26.   
  27.     public String getImage() {  
  28.         return image;  
  29.     }  
  30.   
  31.     public void setImage(String image) {  
  32.         this.image = image;  
  33.     }  
  34.   
  35.     public String[] getRegions() {  
  36.         return regions;  
  37.     }  
  38.   
  39.     public void setRegions(String[] regions) {  
  40.         this.regions = regions;  
  41.     }  
  42.   
  43.     public int getNumberSold() {  
  44.         return numberSold;  
  45.     }  
  46.   
  47.     public void setNumberSold(int numberSold) {  
  48.         this.numberSold = numberSold;  
  49.     }  
  50. }  

然后定义InputIterator这里定义消费者是List<Object>,并对list进行遍历放入payload中:

[java] view plain copy
  1. package com.lucene.suggest;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.ObjectOutputStream;  
  6. import java.io.UnsupportedEncodingException;  
  7. import java.util.Comparator;  
  8. import java.util.HashSet;  
  9. import java.util.Iterator;  
  10. import java.util.Set;  
  11.   
  12. import org.apache.lucene.search.suggest.InputIterator;  
  13. import org.apache.lucene.util.BytesRef;  
  14.   
  15. public class ProductIterator implements InputIterator {  
  16.     private Iterator<Product> productIterator;  
  17.     private Product currentProduct;  
  18.   
  19.     ProductIterator(Iterator<Product> productIterator) {  
  20.         this.productIterator = productIterator;  
  21.     }  
  22.   
  23.     public boolean hasContexts() {  
  24.         return true;  
  25.     }  
  26.   
  27.     /** 
  28.      * 是否有设置payload信息 
  29.      */  
  30.     public boolean hasPayloads() {  
  31.         return true;  
  32.     }  
  33.   
  34.     public Comparator<BytesRef> getComparator() {  
  35.         return null;  
  36.     }  
  37.   
  38.     public BytesRef next() {  
  39.         if (productIterator.hasNext()) {  
  40.             currentProduct = productIterator.next();  
  41.             try {  
  42.                 return new BytesRef(currentProduct.getName().getBytes("UTF8"));  
  43.             } catch (UnsupportedEncodingException e) {  
  44.                 throw new RuntimeException("Couldn't convert to UTF-8",e);  
  45.             }  
  46.         } else {  
  47.             return null;  
  48.         }  
  49.     }  
  50.   
  51.     public BytesRef payload() {  
  52.         try {  
  53.             ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  54.             ObjectOutputStream out = new ObjectOutputStream(bos);  
  55.             out.writeObject(currentProduct);  
  56.             out.close();  
  57.             return new BytesRef(bos.toByteArray());  
  58.         } catch (IOException e) {  
  59.             throw new RuntimeException("Well that's unfortunate.");  
  60.         }  
  61.     }  
  62.     public Set<BytesRef> contexts() {  
  63.         try {  
  64.             Set<BytesRef> regions = new HashSet<BytesRef>();  
  65.             for (String region : currentProduct.getRegions()) {  
  66.                 regions.add(new BytesRef(region.getBytes("UTF8")));  
  67.             }  
  68.             return regions;  
  69.         } catch (UnsupportedEncodingException e) {  
  70.             throw new RuntimeException("Couldn't convert to UTF-8");  
  71.         }  
  72.     }  
  73.   
  74.     
  75.     public long weight() {  
  76.         return currentProduct.getNumberSold();  
  77.     }  
  78. }  

编写测试类
[java] view plain copy
  1. package com.lucene.suggest;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.IOException;  
  5. import java.io.ObjectInputStream;  
  6. import java.nio.file.Paths;  
  7. import java.util.ArrayList;  
  8. import java.util.HashSet;  
  9. import java.util.List;  
  10.   
  11. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  12. import org.apache.lucene.search.suggest.Lookup.LookupResult;  
  13. import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester;  
  14. import org.apache.lucene.store.Directory;  
  15. import org.apache.lucene.store.FSDirectory;  
  16. import org.apache.lucene.util.BytesRef;  
  17.   
  18. public class SuggestProducts {  
  19.     private static void lookup(AnalyzingInfixSuggester suggester, String name,  
  20.             String region) throws IOException {  
  21.         HashSet<BytesRef> contexts = new HashSet<BytesRef>();  
  22.         contexts.add(new BytesRef(region.getBytes("UTF8")));  
  23.         List<LookupResult> results = suggester.lookup(name, contexts, 2truefalse);  
  24.         System.out.println("-- \"" + name + "\" (" + region + "):");  
  25.         for (LookupResult result : results) {  
  26.             System.out.println(result.key);  
  27.             BytesRef bytesRef = result.payload;  
  28.             ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bytesRef.bytes));  
  29.             Product product = null;  
  30.             try {  
  31.                 product = (Product)is.readObject();  
  32.             } catch (ClassNotFoundException e) {  
  33.                 // TODO Auto-generated catch block  
  34.                 e.printStackTrace();  
  35.             }  
  36.             System.out.println("product-Name:" + product.getName());  
  37.             System.out.println("product-regions:" + product.getRegions());  
  38.             System.out.println("product-image:" + product.getImage());  
  39.             System.out.println("product-numberSold:" + product.getNumberSold());  
  40.         }  
  41.         System.out.println();  
  42.     }  
  43.   
  44.     public static void main(String[] args) {  
  45.         try {  
  46.             Directory indexDir = FSDirectory.open(Paths.get("suggestPath"new String[0]));  
  47.             StandardAnalyzer analyzer = new StandardAnalyzer();  
  48.             AnalyzingInfixSuggester suggester = new AnalyzingInfixSuggester(indexDir, analyzer);  
  49.             ArrayList<Product> products = new ArrayList<Product>();  
  50.             products.add(new Product("Electric Guitar",  
  51.                     "http://images.example/electric-guitar.jpg"new String[] {  
  52.                             "US""CA" }, 100));  
  53.             products.add(new Product("Electric Train",  
  54.                     "http://images.example/train.jpg"new String[] { "US",  
  55.                             "CA" }, 100));  
  56.             products.add(new Product("Acoustic Guitar",  
  57.                     "http://images.example/acoustic-guitar.jpg"new String[] {  
  58.                             "US""ZA" }, 80));  
  59.             products.add(new Product("Guarana Soda",  
  60.                     "http://images.example/soda.jpg",  
  61.                     new String[] { "ZA""IE" }, 130));  
  62.   
  63.             suggester.build(new ProductIterator(products.iterator()));  
  64.   
  65.             lookup(suggester, "Gu""US");  
  66.             lookup(suggester, "Gu""ZA");  
  67.             lookup(suggester, "Gui""CA");  
  68.             lookup(suggester, "Electric guit""US");  
  69.             suggester.refresh();  
  70.         } catch (IOException e) {  
  71.             System.err.println("Error!");  
  72.         }  
  73.     }  
  74. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多