Lucene在项目中的实际应用(索引的增删改查)

原创
2016/05/26 15:10
阅读数 195

对于电商网站而言,商品的关键字搜索至关重要,提到搜索,好像apach的Lucene是大家都在用的,所以研究了一番,懂了一丢丢



一、创建需要检索的实体。首先,需要将数据库的商品数据读取出来,取出需要检索的字段的内容,存到一个实体中我定义的是LucenePar,代码如下:

*** <p>Title: lucenePar</p>
* <p>Description: 创建索引的实体</p>
* @author HTY
* @date 2016-5-26 上午10:31:28
*/
public class LucenePar {
    //商品id
    private String id;
    //用户id
    private String uid;
    //商品名称
    private String name;
    //商品价格
    private String pice;
    //商品品牌
    private String brand;
    //商品描述
    private String account;
    //搜索关键字
    private String scope;
    //商品详情
    private String note;

get和set方法就不一一罗列了。


二、新建一个创建索引的类。用于创建索引或是读取文件,用来操作(增、删、改)索引库。

// 数据源路径,可不要,这个是读取文件,对文件检索时需要的
    static String dspath = "E:/mylucene/lucenes/IndexWriter.txt";
    //存放索引文件的位置,即索引库
    static String indexpath = "E:/mylucene/luceneIndex";
    //分词器
    static Analyzer analyzer = new StandardAnalyzer();
    
    /**
     * 创建索引,会抛异常,因为没对索引库进行保存
     * 
     * IndexWriter 用来操作(增、删、改)索引库的
     */
    public static void createIndex() throws Exception {
        //Directory dir=FSDirectory.getDirectory(indexpath);
        //内存存储:优点速度快,缺点程序退出数据就没了,所以记得程序退出时保存索引库,已FSDirectory结合使用
        //由于此处只暂时保存在内存中,程序退出时没进行索引库保存,因此在搜索时程序会报错
        Directory dir=new RAMDirectory();
        File file = new File(dspath);
        //Document存放经过组织后的数据源,只有转换为Document对象才可以被索引和搜索到
        Document doc = new Document();
        //文件名称
        doc.add(new Field("name", file.getName(), Store.YES, Index.ANALYZED));
        //检索到的内容
        doc.add(new Field("content", readFileContent(file), Store.YES, Index.ANALYZED));
        //文件大小
        doc.add(new Field("size", NumberTools.longToString(file.length()),
                Store.YES, Index.NOT_ANALYZED));
        //检索到的文件位置
        doc.add(new Field("path", file.getAbsolutePath(), Store.YES, Index.NOT_ANALYZED));

        // 建立索引
        //第一种方式
        IndexWriter indexWriter = new IndexWriter(indexpath, analyzer, MaxFieldLength.LIMITED);
        //第二种方式
//            IndexWriter indexWriter = new IndexWriter(dir, analyzer, MaxFieldLength.LIMITED);
        indexWriter.addDocument(doc);
        // 优化操作
        indexWriter.commit();
        indexWriter.optimize();
        indexWriter.close();
    }
    //传参数来创建索引,适用于对象创建索引
    public static void createIndexBy(LucenePar lucenePar) throws Exception{
        Directory dir=new RAMDirectory();
        //Document存放经过组织后的数据源,只有转换为Document对象才可以被索引和搜索到
        Document doc = new Document();
        //商品id
        doc.add(new Field("id", lucenePar.getId(), Store.YES, Index.ANALYZED));
        //用户id
        doc.add(new Field("uid", lucenePar.getUid(), Store.YES, Index.ANALYZED));
        //商品名称
        doc.add(new Field("name", lucenePar.getName(), Store.YES, Index.ANALYZED));
        //商品价格
        doc.add(new Field("price", lucenePar.getPice(), Store.YES, Index.ANALYZED));
        //商品品牌
        doc.add(new Field("brand", lucenePar.getBrand(), Store.YES, Index.ANALYZED));
        //商品描述
        doc.add(new Field("account", lucenePar.getAccount(), Store.YES, Index.ANALYZED));
        //搜索关键字
        doc.add(new Field("scope", lucenePar.getScope(), Store.YES, Index.ANALYZED));
        //商品详情
        doc.add(new Field("note", lucenePar.getNote(), Store.YES, Index.ANALYZED));
        // 建立索引
        IndexWriter indexWriter = new IndexWriter(indexpath, analyzer, MaxFieldLength.LIMITED);
        //第二种方式
//        IndexWriter indexWriter = new IndexWriter(dir, analyzer, MaxFieldLength.LIMITED);
        indexWriter.addDocument(doc);
        // 优化操作
        indexWriter.commit();
        indexWriter.optimize();
        indexWriter.close();
    }

    //传参数来创建索引,适用于对象创建索引
    public static void createIndexBy(LucenePar lucenePar) throws Exception{
         //Directory dir=FSDirectory.getDirectory(indexpath);
        //内存存储:优点速度快,缺点程序退出数据就没了,所以记得程序退出时保存索引库,已FSDirectory结合使用
        //由于此处只暂时保存在内存中,程序退出时没进行索引库保存,因此在搜索时程序会报错
        Directory dir=new RAMDirectory();
        Date date1 = new Date();
        //Document存放经过组织后的数据源,只有转换为Document对象才可以被索引和搜索到
        Document doc = new Document();
        //商品id
        doc.add(new Field("id", lucenePar.getId(), Store.YES, Index.ANALYZED));
        //用户id
        doc.add(new Field("uid", lucenePar.getUid(), Store.YES, Index.ANALYZED));
        //商品名称
        doc.add(new Field("name", lucenePar.getName(), Store.YES, Index.ANALYZED));
        //商品价格
        doc.add(new Field("price", lucenePar.getPice(), Store.YES, Index.ANALYZED));
        //商品品牌
        doc.add(new Field("brand", lucenePar.getBrand(), Store.YES, Index.ANALYZED));
        //商品描述
        doc.add(new Field("account", lucenePar.getAccount(), Store.YES, Index.ANALYZED));
        //搜索关键字
        doc.add(new Field("scope", lucenePar.getScope(), Store.YES, Index.ANALYZED));
        //商品详情
        doc.add(new Field("note", lucenePar.getNote(), Store.YES, Index.ANALYZED));
        // 建立索引
        IndexWriter indexWriter = new IndexWriter(indexpath, analyzer, MaxFieldLength.LIMITED);
        //第二种方式
//        IndexWriter indexWriter = new IndexWriter(dir, analyzer, MaxFieldLength.LIMITED);
        indexWriter.addDocument(doc);
        // 优化操作
        indexWriter.commit();
        indexWriter.optimize();
        indexWriter.close();
        Date date2 = new Date();
        System.out.println("创建索引耗时:" + (date2.getTime() - date1.getTime()) + "ms\n");
    }
    //更新索引
    public static void updateIndexBy(LucenePar lucenePar) throws Exception{
        Directory dir=new RAMDirectory();
        Date date1 = new Date();
        //Document存放经过组织后的数据源,只有转换为Document对象才可以被索引和搜索到
        Document doc = new Document();
        //商品id
        doc.add(new Field("id", lucenePar.getId(), Store.YES, Index.ANALYZED));
        //用户id
        doc.add(new Field("uid", lucenePar.getUid(), Store.YES, Index.ANALYZED));
        //商品名称
        doc.add(new Field("name", lucenePar.getName(), Store.YES, Index.ANALYZED));
        //商品价格
        doc.add(new Field("price", lucenePar.getPice(), Store.YES, Index.ANALYZED));
        //商品品牌
        doc.add(new Field("brand", lucenePar.getBrand(), Store.YES, Index.ANALYZED));
        //商品描述
        doc.add(new Field("account", lucenePar.getAccount(), Store.YES, Index.ANALYZED));
        //搜索关键字
        doc.add(new Field("scope", lucenePar.getScope(), Store.YES, Index.ANALYZED));
        //商品详情
        doc.add(new Field("note", lucenePar.getNote(), Store.YES, Index.ANALYZED));
        // 建立索引
        IndexWriter indexWriter = new IndexWriter(indexpath, analyzer, MaxFieldLength.LIMITED);
        //第二种方式
//        IndexWriter indexWriter = new IndexWriter(dir, analyzer, MaxFieldLength.LIMITED);
        indexWriter.updateDocument(new Term("id","745"), doc);
        // 优化操作
        indexWriter.commit();
        indexWriter.optimize();
        indexWriter.close();
        Date date2 = new Date();
        System.out.println("更新索引耗时:" + (date2.getTime() - date1.getTime()) + "ms\n");
    }
    //删除索引
    public static void deleteIndexBy(List<String> list,String queryString) throws Exception{
        Directory dir=new RAMDirectory();
        Date date1 = new Date();
        IndexWriter indexWriter = new IndexWriter(indexpath, analyzer, MaxFieldLength.LIMITED);
        String[] fields = new String[list.size()];
        int i = 0;
        for(String str:list){
            fields[i] = str;
            i++;
        }
        QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
        Query query = queryParser.parse(queryString);
        indexWriter.deleteDocuments(query);
        indexWriter.close();
        Date date2 = new Date();
        System.out.println("删除索引耗时:" + (date2.getTime() - date1.getTime()) + "ms\n");
    }
    /**
     * 读取文件内容
     */
    public static String readFileContent(File file) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            StringBuffer content = new StringBuffer();
            for (String line = null; (line = reader.readLine()) != null;) {
                content.append(line).append("\n");
            }
            reader.close();
            return content.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


三、新建索引的查询类。用于查询索引文件的内容并取到相应的值。

// 数据源路径
    // static String dspath = "E:/mylucene/lucenes/IndexWriter.txt";
    //存放索引文件的位置,即索引库
    static String indexpath = "E:/mylucene/luceneIndex";
    //分词器
    static Analyzer analyzer = new StandardAnalyzer();
    /**
     * 搜索
     * para list:需要检索的字段名,queryString:搜索文字
     * IndexSearcher 用来在索引库中进行查询
     */
    public static void search(List<String> list,String queryString) throws Exception {
        //请求字段
        //String queryString = "document";

        // 1,把要搜索的文本解析为 Query
        String[] fields = new String[list.size()];
        int i = 0;
        for(String str:list){
            fields[i] = str;
            i++;
        }

        QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
        Query query = queryParser.parse(queryString);

        // 2,进行查询,从索引库中查找
        IndexSearcher indexSearcher = new IndexSearcher(indexpath);
        Filter filter = null;
        TopDocs topDocs = indexSearcher.search(query, filter, 10000);
        System.out.println("总共有【" + topDocs.totalHits + "】条匹配结果");

        // 3,打印结果
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            // 文档内部编号
            int index = scoreDoc.doc; 
            // 根据编号取出相应的文档
            Document doc = indexSearcher.doc(index);
            System.out.println("------------------------------");
            System.out.println("id = " + doc.get("id"));
            System.out.println("uid = " + doc.get("uid"));
            System.out.println("name = " + doc.get("name"));
            System.out.println("price = " + doc.get("price"));
            System.out.println("brand = " + doc.get("brand"));
            System.out.println("account = " + doc.get("account"));
            System.out.println("scope = " + doc.get("scope"));
            System.out.println("note = " + doc.get("note"));
        }
    }
    public static void search2(){
//        // 采用正向最大匹配的中文分词算法
//        private static Analyzer analyzer = new MMAnalyzer();

        Directory directory = new RAMDirectory();
        String fieldName = "text";
        String text = "据路透社报道,印度尼西亚社会事务部一官员星期二(29日)表示,"
                + "日惹市附近当地时间27日晨5时53分发生的里氏6.2级地震已经造成至少5427人死亡,"
                + "20000余人受伤,近20万人无家可归。"; // 检索内容

        try {
            IndexWriter iwriter = new IndexWriter(directory, analyzer, true);
            iwriter.setMaxFieldLength(25000);
            Document doc = new Document();
            doc.add(new Field(fieldName, text, Field.Store.YES,
                    Field.Index.TOKENIZED,
                    Field.TermVector.WITH_POSITIONS_OFFSETS));
            iwriter.addDocument(doc);
            iwriter.close();

            IndexSearcher isearcher = new IndexSearcher(directory);
            QueryParser parser = new QueryParser(fieldName, analyzer);
            Query query = parser.parse("印度尼西亚 6.2级地震20万官员受伤");// 检索词
            Hits hits = isearcher.search(query);
            System.out.println("命中:" + hits.length());

            Highlighter highlighter = new Highlighter(new QueryScorer(query));
            for (int i = 0; i < hits.length(); i++) {
                text = hits.doc(i).get(fieldName);
                TermPositionVector tpv = (TermPositionVector) IndexReader.open(
                        directory).getTermFreqVector(hits.id(i), fieldName);
                TokenStream tokenStream = TokenSources.getTokenStream(tpv);
                String result = highlighter.getBestFragments(tokenStream, text,
                        3, "...");
                System.out.println("内容:" + result);
            }

            isearcher.close();
            directory.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


四、创建一个service。处理所有关于搜索的问题,提供接口供其他模块调用,用于测试只写一个main方法。

public static void main(String[] args){
        LucenePar lucenePar = new LucenePar();

       lucenePar.setId("743");
        lucenePar.setName("青豌豆小吃(混装)修ddd");
        lucenePar.setPice("15.8");
        lucenePar.setBrand("好想你");
        lucenePar.setUid("1888");
        lucenePar.setAccount("增强记忆力的最佳选择,青豌豆!!!");
        lucenePar.setScope("多一两");
        lucenePar.setNote("青豌豆");
        List<String> list = new ArrayList<String>();
        list.add("name");
        list.add("brand");
        list.add("note");
        try {
            //新增-查询-更新-查询-删除-查询
            //creatIndex.createIndexBy(lucenePar);
            searchIndex.search(list, "青豌豆");
            creatIndex.updateIndexBy(lucenePar);
            searchIndex.search(list, "青豌豆");
            creatIndex.deleteIndexBy(list, "青豌豆");
            searchIndex.search(list, "青豌豆");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


五、效果

展开阅读全文
打赏
0
7 收藏
分享
加载中
更多评论
打赏
0 评论
7 收藏
0
分享
返回顶部
顶部