Lucene6.6.2之代码示例

这个是以下代码的完整项目,或许对你们有所帮助 《Lucene6.6.2API示例下载》

项目搭建

这里写图片描述

网上关于Luence6.x及以上的资料比较少,大多都是4.x的,API修改的修改、废弃的废弃

这里就简单介绍一些常用API的使用

采集数据

  • 对于互联网中的数据,使用爬虫工具(HTTP工具)将网页爬取到本地
  • 对于数据库中的数据,使用JDBC程序进行数据采集
  • 对于文件系统的数据,使用IO流采集

这里的原始数据来自数据库
这里写图片描述
对应的是Java中的POJO类

public class Book {
    // 图书ID
    private Integer id;
    // 图书名称
    private String name;
    // 图书价格
    private Float price;
    // 图书图片
    private String pic;
    // 图书描述
    private String description;
    // 省略getter、setter方法
}

使用JDBC采集数据后封装成Java对象,重点不在这,所以不多做介绍


创建索引、及维护索引,IndexWriter

IndexManager.java

@Test
public void createIndex() throws Exception {
    // 清除原先的数据
    deleteIndex();

    // 采集数据
    List<Book> findAllBooks = new BookDaoImpl().findAllBooks();

    // 将采集到的数据封装到Document对象中
    // 一个对象(记录)= 一个Document
    // 一个属性(字段)= 一个Field
    List<Document> documents = new ArrayList<Document>();
    Document document = null;
    for (Book book : findAllBooks) {
        document = new Document();

        // Store:Yes则将数据存到文档域中,NO则相反
        // IntPoint:不分词、索引、不存储,可用于范围搜索,与FloatPoint、DoublePoint、LongPoint用法一样
        Field idIndex = new IntPoint("idIndex", book.getId());
        // 因为IntPoint只生成索引、存储到索引库,所以如果搜索时需要此数据,则需要再存储一份到文档库
        Field idString = new StoredField("idString", book.getId().toString());
        // TextField:分词、索引、存储
        Field name = new TextField("name", book.getName(), Store.YES);
        // FloatDocValuesField:不分词、索引、不存储,可用于排序,与DoubleDocValuesField、NumericDocValuesField、SortedNumericDocValuesField一样
        Field priceIndex = new FloatDocValuesField("priceIndex", book.getPrice());
        Field priceString = new StoredField("priceString", book.getPrice().toString());
        // StoredField:不分词、不索引、存储
        Field pic = new StoredField("pic", book.getPic());
        // TextField:分词、索引、不存储
        Field description = new TextField("description", book.getDescription(), Store.NO);

        // 将field域设置到Document对象中
        document.add(idIndex);
        document.add(idString);
        document.add(name);
        document.add(priceIndex);
        document.add(priceString);
        document.add(pic);
        document.add(description);

        documents.add(document);
    }

    // 创建分词器,自带的标准分词器
    Analyzer analyzer = new StandardAnalyzer();

    // 创建IndexWriter
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    IndexWriter writer = new IndexWriter(directory, config);

    // 通过IndexWriter把Document写到索引库中
    for (Document doc : documents) {
        writer.addDocument(doc);
    }
    // 关闭资源
    writer.close();
}

@Test
public void deleteIndex() throws Exception {
    // 创建分词器,标准分词器
    Analyzer analyzer = new StandardAnalyzer();

    // 创建IndexWriter
    IndexWriterConfig cfg = new IndexWriterConfig(analyzer);
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
    // 创建IndexWriter
    IndexWriter writer = new IndexWriter(directory, cfg);

    // Terms
    // writer.deleteDocuments(new Term("idIndex", "1"));

    // 删除全部(慎用)
    writer.deleteAll();

    writer.close();
}

@Test
public void updateIndex() throws Exception {
    // 创建分词器,标准分词器
    Analyzer analyzer = new StandardAnalyzer();

    IndexWriterConfig cfg = new IndexWriterConfig(analyzer);
    Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
    // 创建IndexWriter
    IndexWriter writer = new IndexWriter(directory, cfg);

    // 第一个参数:指定查询条件
    // 第二个参数:修改之后的对象
    // 修改时如果根据查询条件,可以查询出结果,则将以前的删掉,然后覆盖新的Document对象,如果没有查询出结果,则新增一个Document
    // 修改流程即:先查询,再删除,在添加
    Document doc = new Document();
    doc.add(new TextField("name", "javaSE", Store.YES));
    writer.updateDocument(new Term("name", "javase"), doc);

    writer.close();
}

搜索,IndexSearch

IndexSearch.java

private void doSearch(Query query, Sort sort) {
    // 创建IndexSearcher
    // 指定索引库的地址
    try {
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
        IndexReader reader = DirectoryReader.open(directory);
        IndexSearcher searcher = new IndexSearcher(reader);

        // 通过searcher来搜索索引库
        // 第二个参数:指定需要显示的顶部记录的N条
        // 第三个参数:排序条件
        TopDocs topDocs = null;
        if(sort != null) {
            topDocs = searcher.search(query, 10, sort);
        }
        else {
            topDocs = searcher.search(query, 10);
        }

        // 根据查询条件匹配出的记录总数
        int count = topDocs.totalHits;
        System.out.println("匹配出的记录总数:" + count);
        // 根据查询条件匹配出的记录
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        for (ScoreDoc scoreDoc : scoreDocs) {
            // 获取文档的ID
            int docId = scoreDoc.doc;

            // 通过ID获取文档
            Document doc = searcher.doc(docId);
            System.out.println("商品ID:" + Integer.parseInt(doc.get("idString")));
            System.out.println("商品名称:" + doc.get("name"));
            System.out.println("商品价格:" + Float.parseFloat(doc.get("priceString")));
            System.out.println("商品图片地址:" + doc.get("pic"));
            System.out.println("==========================");
            // System.out.println("商品描述:" + doc.get("description"));
        }
        // 关闭资源
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Test
public void indexSearch() throws Exception {
    // 创建query对象
    // 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
    // 第一个参数:默认搜索的域的名称
    QueryParser parser = new QueryParser("description", new StandardAnalyzer());

    // 通过queryparser来创建query对象
    // 参数:输入的lucene的查询语句(关键字一定要大写)
//      Query query = parser.parse("java AND name:lucene");
//      Query query = parser.parse("java OR name:lucene");
    Query query = parser.parse("java NOT name:lucene");

    // 创建浮点数排序字段,默认为false:升序;true:降序
    SortField sortField = new SortField("priceIndex", Type.FLOAT, false);
    Sort sort = new Sort();
    sort.setSort(sortField);

    doSearch(query, sort);
}

@Test
public void termQuery() {
    // 创建TermQuery对象
    Query query = new TermQuery(new Term("description", "java"));

    doSearch(query, null);
}

@Test
public void newRangeQuery() {

    // 创建IntPoint对象,范围查找
    Query query = IntPoint.newRangeQuery("idIndex", 2, 3);
    doSearch(query, null);
}

@Test
public void booleanQuery() {
    // 创建TermQuery对象
    Query query1 = new TermQuery(new Term("name", "java"));
    // 创建NumericRangeQuery对象
    // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
    Query query2 = IntPoint.newRangeQuery("idIndex", 1, 5);

    // 组合关系代表的意思如下:
    // 1、MUST和MUST表示“与”的关系,即“交集”。
    // 2、MUST和MUST_NOT前者包含后者不包含。
    // 3、MUST_NOT和MUST_NOT没意义
    // 4、SHOULD与MUST表示MUST,SHOULD失去意义;
    // 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。
    // 6、SHOULD与SHOULD表示“或”的概念。

    BooleanClause bc1 = new BooleanClause(query1, Occur.MUST);
    BooleanClause bc2 = new BooleanClause(query2, Occur.MUST);
    // Lucene 6.x中BooleanQuery与4.x中的BooleanQuery用法不一样
    BooleanQuery boolQuery = new BooleanQuery.Builder().add(bc1).add(bc2).build();
    System.out.println(boolQuery);

    doSearch(boolQuery, null);
}

@Test
public void multiFieldQueryParser() throws Exception {
    // 创建MultiFieldQueryParser
    // 默认搜索的多个域的域名
    String[] fields = { "name", "description" };
    Analyzer analyzer = new StandardAnalyzer();
    // 
    Map<String, Float> boosts = new HashMap<String, Float>();
    boosts.put("name", 200f);
    MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer, boosts);

    //Query query = parser.parse("java");
    Query query = parser.parse("name:java OR description:lucene");

    System.out.println(query);

    doSearch(query, null);
}

官方文档:《Lucene 6.2.1 core API》


相关度排序

什么是相关度排序

相关度排序就是查询关键字与查询结果的匹配相关度。匹配越高的越靠前。Lucene是通过打分来进行相关度排序的。

打分分两步:

1、 根据词计算词的权重
2、 根据词的权重进行打分

词的权重:词指的就是term。也就是说一个term对一个文档的重要性,就叫词的权重。

影响词的权重的方式有两种:

Tf:词在同一个文档中出现的频率

Tf越高,说明词的权重越高

Df:词在多个文档中出现的频率

Df越高,说明词的权重越低

以上是自然打分的规则。

设置boost值影响打分

Boost:加权值,默认是1.0f。Boost值是设置到Field域上的。

设置加权值可以在创建索引时设置,也可以在查询时设置。

创建索引时设置boost值

// 图书ID
// 不分词、索引、存储 StringField
Field id = new StringField("id", "1", Store.YES);
// 图书描述
// 分词、索引、不存储 TextField
Field description = new TextField("description", "这是一本书", Store.NO);

// 设置boost值
if (book.getId() == 4)
    description.setBoost(100f);

// 将field域设置到Document对象中
document.add(id);
document.add(description);

搜索时设置boost值

在MultiFieldQueryParser创建时设置boost值。

@Test
public void multiFieldQueryParser() throws Exception {
    // 创建MultiFieldQueryParser
    // 默认搜索的多个域的域名
    String[] fields = { "name", "description" };
    Analyzer analyzer = new StandardAnalyzer();
    Map<String, Float> boosts = new HashMap<String, Float>();
    boosts.put("name", 200f);
    MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer, boosts);

    // Query query = parser.parse("name:lucene OR description:lucene");
    Query query = parser.parse("java");

    System.out.println(query);

    doSearch(query);
}

猜你喜欢

转载自blog.csdn.net/code_shadow/article/details/80694801
今日推荐