zoukankan      html  css  js  c++  java
  • (四)Lucene——搜索和相关度排序

    1. 搜索

    1.1 创建查询对象的方式

    • 通过Query子类来创建查询对象

    Query子类常用的有TermQuery、NumericRangeQuery、BooleanQuery

    特点:不能输入lucene的查询语法不需要指定分词器

    • 通过QueryParser来创建查询对象(常用)

    QueryParser、MultiFieldQueryParser

    特点:可以输入lucene的查询语法可以指定分词器

    1.2 通过Query子类来创建查询对象

    1.2.1 TermQuery(精确的词项查询)

    @Test
        public void termQuery() {
            // 创建TermQuery对象
            Query query = new TermQuery(new Term("description", "java"));
            doSearch(query);
        }
    private void doSearch(Query query) {
            // 创建IndexSearcher
            // 指定索引库的地址
            try {
                File indexFile = new File("D:\DBIndex\");
                Directory directory = FSDirectory.open(indexFile);
                IndexReader reader = DirectoryReader.open(directory);
                IndexSearcher searcher = new IndexSearcher(reader);
                // 通过searcher来搜索索引库
                // 第二个参数:指定需要显示的顶部记录的N条
                TopDocs 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:" + doc.get("id"));
                    System.out.println("商品名称:" + doc.get("name"));
                    System.out.println("商品价格:" + doc.get("price"));
                    System.out.println("商品图片地址:" + doc.get("pic"));
                    System.out.println("==========================");
                    // System.out.println("商品描述:" + doc.get("description"));
                }
                // 关闭资源
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    1.2.2  NumericRangeQuery(数字范围查询)

    @Test
        public void numericRangeQuery() {
            // 创建NumericRangeQuery对象
            // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
            Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true, false);
            doSearch(query);
        }

    1.2.3 BooleanQuery(组合查询)

    @Test
        public void booleanQuery() {
            // 创建BooleanQuery
            BooleanQuery query = new BooleanQuery();
            // 创建TermQuery对象
            Query q1 = new TermQuery(new Term("description", "lucene"));
            // 创建NumericRangeQuery对象
            // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
            Query q2 = NumericRangeQuery.newFloatRange("price", 55f, 60f, true, false);
    
            // 组合关系代表的意思如下:
            // 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表示“或”的概念。
    
            query.add(q1, Occur.MUST_NOT);
            query.add(q2, Occur.MUST_NOT);
    
            doSearch(query);
        }

    1.3 通过QueryParser来创建查询对象

    1.3.1 QueryParser

    通过QueryParser来创建query对象,可以指定分词器,搜索时的分词器和创建该索引的分词器一定要一致。还可以输入查询语句。

    @Test
        public void indexSearch() throws Exception {
            // 创建query对象
            // 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
            // 第一个参数:默认搜索的域的名称
            QueryParser parser = new QueryParser("description", new StandardAnalyzer());
    
            // 通过queryparser来创建query对象
            // 参数:输入的lucene的查询语句(关键字一定要大写)
            Query query = parser.parse("description:java AND lucene");
    
            doSearch(query);
        }

    1.3.2 MultiFieldQueryParser(多域查询)

    @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);
        }

    1.3.3 查询语法

    (1)基础的查询语法,关键词查询

    域名+“:”+搜索的关键字

    例如:content:java

    (2)范围查询

    域名+:+[最小值 TO 最大值]

    例如:size:[1 TO 1000]

    注意:QueryParser不支持对数字范围的搜索,它支持字符串范围。数字范围搜索建议使用NumericRangeQuery

    (3)组合条件查询

    Occur.MUST 查询条件必须满足,相当于and

    +(加号)

    Occur.SHOULD 查询条件可选,相当于or

    空(不用符号)

    Occur.MUST_NOT 查询条件不能满足,相当于not非

    -(减号)

     

     

     

     

     

    (3.1)+条件1 +条件2:两个条件之间是并且的关系and

    例如:+filename:apache +content:apache

    (3.2)+条件1 条件2:必须满足第一个条件,忽略第二个条件

    例如:+filename:apache content:apache

    (3.3)条件1 条件2:两个条件满足其一即可。

    例如:filename:apache content:apache

    (3.4)-条件1 条件2:必须不满足条件1,要满足条件2

    例如:-filename:apache content:apache

    (4)组合查询(3)的第二种写法

    • 条件1 AND 条件2
    • 条件1 OR 条件2
    • 条件1 NOT 条件2

     1.4 TopDocs

    Lucene搜索结果可通过TopDocs遍历,TopDocs类提供了少量的属性,如下:

    方法或属性

    说明

    totalHits

    匹配搜索条件的总记录数

    scoreDocs

    顶部匹配记录

    注意:

    Search方法需要指定匹配记录数量nindexSearcher.search(query, n)

    TopDocs.totalHits:是匹配索引库中所有记录的数量

    TopDocs.scoreDocs:匹配相关度高的前边记录数组,scoreDocs的长度小于等于search方法指定的参数n

    2. 相关度排序

    2.1 什么是相关度排序

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

    2.1.1 打分分两步:

    step1:根据词计算词的权重

    step2:根据词的权重进行打分

    2.1.2 词的权重

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

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

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

         Tf越高说明词的权重越高

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

         Df越高说明词的权重越低

    以上是自然打分的规则。

    2.2 设置boost值影响打分

    Boost:加权值默认是1.0f

    设置加权值可以在创建索引时(如下代码)设置也可以在查询时(见1.3.2 MultiFieldQueryParser(多域查询)设置

    for (Book book : list) {
                document = new Document();
                // store:如果是yes,则说明存储到文档域中
                // 图书ID
                // 不分词、索引、存储 StringField
                Field id = new StringField("id", book.getId().toString(), Store.YES);
                // 图书名称
                // 分词、索引、存储 TextField
                Field name = new TextField("name", book.getName(), Store.YES);
                ············
    // 设置boost值 if (book.getId() == 4) description.setBoost(100f); // 将field域设置到Document对象中 document.add(id);        ············· }

    Boost值是设置到Field域上的

  • 相关阅读:
    基于VB6.0的MICAPS风云二号卫星云图转化实例(转载)
    .CS文件编译生成.DLL文件 .EXE文件(C#网络搜集)(转)
    SQL SERVER 2005及以上查看各表的记录数及占空间大小
    sql2008生成insert语句
    jdk chm文档下载地址
    source insight 解决自动缩进 和 TAB键=4个SPACE
    Hibernate的Criteria的使用
    java多线程协作: wait/notifyAll ( Cooperation between tasks )
    Eclipse 去掉JavaScript Validator
    jquery 插件示例, jquery popup 插件
  • 原文地址:https://www.cnblogs.com/zjfjava/p/7638996.html
Copyright © 2011-2022 走看看