• Lucene第二讲——索引与搜索


    一、Feild域

      1.Field域的属性

        是否分词:Tokenized    

          是对该field存储的内容进行分词分词的目的就是为了索引

          否不需要对field存储的内容进行分词不分词不代表不索引而是将整个内容进行索引

        是否索引:Indexed    

          是将分好的词进行索引索引的目的就是为了搜索

          否不索引也就是不对该field域进行搜索

        是否存储:Stored

          是field域中的内容存储到文档域中存储的目的就是为了搜索页面显示取值用的

          否不将field域中的内容存储到文档域中不存储则搜索页面中没法获取该field域的值

      2.常用Field:

      

    Field

    数据类型

    Analyzed

    是否分词

    Indexed

    是否索引

    Stored

    是否存储

    说明

    StringField(FieldName, FieldValue,Store.YES))

    字符串

    N

    Y

    Y或N

    这个Field用来构建一个字符串Field,但是不会进行分词,会将整个串存储在索引中,比如(订单号,身份证号等)

    是否存储在文档中用Store.YESStore.NO决定

    LongField(FieldName, FieldValue,Store.YES)

    Long

    Y

    Y

    Y或N

    这个Field用来构建一个Long数字型Field,进行分词和索引,比如(价格)

    是否存储在文档中用Store.YESStore.NO决定

    StoredField(FieldName, FieldValue) 

    重载方法,支持多种类型

    N

    N

    Y

    这个Field用来构建不同类型Field

    不分析,不索引,但要Field存储在文档中

    TextField(FieldName, FieldValue, Store.NO)

    TextField(FieldName, reader)

     

    字符串

    Y

    Y

    Y或N

    如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.

        完整类图如下:

        

      按照这个改造入门程序的Field的用法:

            // 创建文档中的Field域,Store可以确定是否存储到文档域中
                // ID,使用StringField;分词:否;索引:是;存储:是
                Field idField = new StringField("id", book.getId().toString(), Field.Store.YES);
                // name 使用TextField;分词:是;索引:是;存储:是
                Field nameField = new TextField("name", book.getName(), Field.Store.YES);
                // price 使用FloatField;分词:是;索引:是;存储:是
                Field priceField = new FloatField("price", book.getPrice(), Field.Store.YES);
                // pic 不分词不索引,但存储
                Field picField = new StoredField("pic", book.getPic());
                // description 分词索引不存储
                Field descriptionField = new TextField("description", book.getDescription(), Field.Store.NO);

      然后删掉索引,重新生成一下索引

     二、索引的维护  

       包含索引的 增删改等维护操作

       1.增加索引:

    调用 indexWriter.addDocument(doc)添加索引。

      //参考入门程序

      2.删除索引:

       根据Term删除:Term是索引库中的最小单位,也就是索引结构图索引域的 组成部分。

    // 删除索引
        @Test
        public void deleteIndex() throws Exception {
            // 1、指定索引库目录
            Directory directory = FSDirectory.open(new File("E:\11-index\0720"));
            // 2、创建IndexWriterConfig
            IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
                    new StandardAnalyzer());
            // 3、 创建IndexWriter
            IndexWriter writer = new IndexWriter(directory, cfg);
            // 4、通过IndexWriter来删除索引
            // b)、删除指定索引
            writer.deleteDocuments(new Term("filename", "apache"));
            // 5、关闭IndexWriter
            writer.close();
        }
    View Code

      //删除的是一个document对象,也就是类似数据库删除一条记录,根据id删除也就相当于SQL中delById()

      想要删除全部:

        writer.deleteAll();

      3.修改索引

      需要先查后改,需要先找到需要修改的索引,再提供新的值即可

    // 修改索引
        @Test
        public void updateIndex() throws Exception {
            // 1、指定索引库目录
            Directory directory = FSDirectory.open(new File("E:\11-index\0720"));
            // 2、创建IndexWriterConfig
            IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
                    new StandardAnalyzer());
            // 3、 创建IndexWriter
            IndexWriter writer = new IndexWriter(directory, cfg);
            // 4、通过IndexWriter来修改索引
            // a)、创建修改后的文档对象
            Document document = new Document();
    
            // 文件名称
            Field filenameField = new StringField("filename", "updateIndex", Store.YES);
            document.add(filenameField);
    
            // 修改指定索引为新的索引
            writer.updateDocument(new Term("filename", "apache"), document);
    
            // 5、关闭IndexWriter
            writer.close();
        }
    View Code

      //若未查询到结果,则直接新增

    三、搜索

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

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

        TermQuery——精确的词项查询

    Query query = new TermQuery(new Term("name", "lucene"))

     

    package com.itheima.lucene.first;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.index.DirectoryReader;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.Term;
    import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.BooleanClause.Occur;
    import org.apache.lucene.search.BooleanQuery;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.NumericRangeQuery;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.ScoreDoc;
    import org.apache.lucene.search.TermQuery;
    import org.apache.lucene.search.TopDocs;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    import org.junit.Test;
    
    /**
     *  
     * <p>
     * Title: IndexSearch
     * </p>
     *  
     * <p>
     * Description: TODO(这里用一句话描述这个类的作用) 
     * <p>
     * <p>
     * Company: www.itcast.com
     * </p>
     *  @author 传智.关云长   @date 2015-12-27 上午11:05:35    @version 1.0
     */
    public class IndexSearch {
    
        private void doSearch(Query query) {
            // 创建IndexSearcher
            // 指定索引库的地址
            try {
                File indexFile = new File("E:\11-index\hm19\");
                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();
            }
        }
    
        @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);
    
        }
    
        @Test
        public void termQuery() {
            // 创建TermQuery对象
            Query query = new TermQuery(new Term("description", "java"));
    
            doSearch(query);
        }
    
        @Test
        public void numericRangeQuery() {
    
            // 创建NumericRangeQuery对象
            // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
            Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
                    false);
    
            doSearch(query);
        }
    
        @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);
        }
    
        @Test
        public void multiFieldQueryParser() throws Exception {
            // 创建7.3.2 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);
        }
    }
    View Code

     

         NumericRangeQuery——数字范围查询

    Query query = NumericRangeQuery.newLongRange("size", 1l, 100l, true,true);
    package com.itheima.lucene.first;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.index.DirectoryReader;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.Term;
    import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.BooleanClause.Occur;
    import org.apache.lucene.search.BooleanQuery;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.NumericRangeQuery;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.ScoreDoc;
    import org.apache.lucene.search.TermQuery;
    import org.apache.lucene.search.TopDocs;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    import org.junit.Test;
    
    /**
     *  
     * <p>
     * Title: IndexSearch
     * </p>
     *  
     * <p>
     * Description: TODO(这里用一句话描述这个类的作用) 
     * <p>
     * <p>
     * Company: www.itcast.com
     * </p>
     *  @author 传智.关云长   @date 2015-12-27 上午11:05:35    @version 1.0
     */
    public class IndexSearch {
    
        private void doSearch(Query query) {
            // 创建IndexSearcher
            // 指定索引库的地址
            try {
                File indexFile = new File("E:\11-index\hm19\");
                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();
            }
        }
    
        @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);
    
        }
    
        @Test
        public void termQuery() {
            // 创建TermQuery对象
            Query query = new TermQuery(new Term("description", "java"));
    
            doSearch(query);
        }
    
        @Test
        public void numericRangeQuery() {
    
            // 创建NumericRangeQuery对象
            // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
            Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
                    false);
    
            doSearch(query);
        }
    
        @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);
        }
    
        @Test
        public void multiFieldQueryParser() throws Exception {
            // 创建7.3.2 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);
        }
    }
    View Code

        BooleanQuery——布尔查询,实现组合条件查询。

    BooleanQuery query = new BooleanQuery();
            Query query1 = new TermQuery(new Term("id", "3"));
            Query query2 = NumericRangeQuery.newFloatRange("price", 10f, 200f,
                    true, true);
    
            //MUST:查询条件必须满足,相当于AND
            //SHOULD:查询条件可选,相当于OR
            //MUST_NOT:查询条件不能满足,相当于NOT非
            query.add(query1, Occur.MUST);
            query.add(query2, Occur.SHOULD);
            
            System.out.println(query);
    package com.itheima.lucene.first;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.index.DirectoryReader;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.Term;
    import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.BooleanClause.Occur;
    import org.apache.lucene.search.BooleanQuery;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.NumericRangeQuery;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.ScoreDoc;
    import org.apache.lucene.search.TermQuery;
    import org.apache.lucene.search.TopDocs;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    import org.junit.Test;
    
    /**
     *  
     * <p>
     * Title: IndexSearch
     * </p>
     *  
     * <p>
     * Description: TODO(这里用一句话描述这个类的作用) 
     * <p>
     * <p>
     * Company: www.itcast.com
     * </p>
     *  @author 传智.关云长   @date 2015-12-27 上午11:05:35    @version 1.0
     */
    public class IndexSearch {
    
        private void doSearch(Query query) {
            // 创建IndexSearcher
            // 指定索引库的地址
            try {
                File indexFile = new File("E:\11-index\hm19\");
                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();
            }
        }
    
        @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);
    
        }
    
        @Test
        public void termQuery() {
            // 创建TermQuery对象
            Query query = new TermQuery(new Term("description", "java"));
    
            doSearch(query);
        }
    
        @Test
        public void numericRangeQuery() {
    
            // 创建NumericRangeQuery对象
            // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
            Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
                    false);
    
            doSearch(query);
        }
    
        @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);
        }
    
        @Test
        public void multiFieldQueryParser() throws Exception {
            // 创建7.3.2 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);
        }
    }
    View Code

     

      2.通过QueryParser来创建查询对象

        QueryParser(可以使用lucene语法,常用)、MultiFieldQueryParser

        QueryParser

        通过QueryParser也可以创建QueryQueryParser提供一个Parse方法,此方法可以直接根据查询语法来查询。Query对象执行的查询语法可通过System.out.println(query);查询。

        示例:

    @Test
        public void testQueryParser() throws Exception {
            // 创建QueryParser
            // 第一个参数:默认域名
            // 第二个参数:分词器
            QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
    // 指定查询语法 ,如果不指定域,就搜索默认的域
            Query query = queryParser.parse("lucene");
            System.out.println(query);
            // 2、 执行搜索
            doSearch(query);
    
        }
    View Code  

        MultiFieldQueryParser——多域查询

    @Test
        public void testMultiFieldQueryParser() throws Exception {
            // 可以指定默认搜索的域是多个
            String[] fields = { "name", "description" };
            // 创建一个MulitFiledQueryParser对象
            QueryParser parser = new MultiFieldQueryParser(fields, new IKAnalyzer());
    // 指定查询语法 ,如果不指定域,就搜索默认的域
            Query query = parser.parse("lucene");
            // 2、 执行搜索
            doSearch(query);
        }
    View Code

      3.查询语法

        1.基础查询语法  

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

        例如:content:java

        2.范围查询

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

        例如:size:[1 TO 1000]

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

        3.条件查询

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

          例如:+filename:apache +content:apache

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

          例如:+filename:apache content:apache

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

          例如:filename:apache content:apache

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

          例如:-filename:apache content:apache

      4.TopDocs

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

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

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

    四、相关度排序

      1.什么是相关度

        相关度排序是查询结果按照与查询关键字的相关性进行排序,越相关的越靠前。比如搜索Lucene”关键字,与该关键字最相关的文章应该排在前边。

      2.相关度打分

      Lucene对查询关键字和索引文档的相关度进行打分,得分高的就排在前边。如何打分呢?Lucene是在用户进行检索时实时根据搜索的关键字计算出来的,分两步:

      1)计算出词(Term)的权重

      2)根据词的权重值,计算文档相关度得分

      什么是词的权重?

      通过索引部分的学习,明确索引的最小单位是一个Term(索引词典中的一个词),搜索也是要从Term中搜索,再根据Term找到文档,Term对文档的重要性称为权重,影响Term权重有两个因素:

      Tf

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

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

          Df

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

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

      以上是自然打分的规则。

      3.设置boost值影响打分

      Boost:加权值,默认是1.0f。

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

      Boost值是设置到Field域上的

        1.创建时指定(常用)

    @Test
        public void setBoost4createIndex() throws Exception {
            // 创建分词器
            Analyzer analyzer = new StandardAnalyzer();
    
            IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_4_10_3,
                    analyzer);
            Directory directory = FSDirectory.open(new File("E:\11-index\0728"));
            // 创建IndexWriter对象,通过它把分好的词写到索引库中
            IndexWriter writer = new IndexWriter(directory, cfg);
    
            Document doc = new Document();
            Field id = new StringField("id", "11", Store.YES);
            Field description = new TextField("description", "测试设置BOOST值 lucene",
                    Store.YES);
            // 设置boost
            description.setBoost(10.0f);
            // 把域添加到文档中
            doc.add(id);
            doc.add(description);
            writer.addDocument(doc);
            // 关闭IndexWriter
            writer.close();
        }
    View Code

        2..MultiFieldQueryParser创建时设置boost

      

     五、中文分词器

       1.什么是中文分词器

      学过英文的都知道,英文是以单词为单位的,单词与单词之间以空格或者逗号句号隔开。而中文则以字为单位,字又组成词,字和词再组成句子。所以对于英文,我们可以简单以空格判断某个字符串是否为一个单词

      比如I love Chinalove China很容易被程序区分开来;但中文“我爱中国”就不一样了,电脑不知道“中国”是一个词语还是“爱中”是一个词语。把中文的句子切分成有意义的词,就是中文分词,也称切词。我爱中国,分词的结果是:我 中国。

      2.Lucene自带分词器

       StandardAnalyzer

      单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”
           效果:爱”

      CJKAnalyzer

      二分法分词:按两个字进行切分。如:“我是中国人”,效果:我是”、是中”、中国“国人”。

      3.第三方中文分词器

      这里暂时只介绍实际使用的: IKAnalyzer

      其它例如 smartcn等暂时不展开。

      如何使用:

        相关的使用步骤可以参见:http://blog.csdn.net/cyxlzzs/article/details/7999212

        1.添加jar

        2.修改分词器:

    // 创建中文分词器
    Analyzer analyzer = new IKAnalyzer();

        3.ikanalyzer包中拷贝配置文件classpath

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
    <properties>  
    
        <comment>IK Analyzer 扩展配置</comment>
        <!-- 用户可以在这里配置自己的扩展字典 -->
         <entry key="ext_dict">dicdata/mydict.dic</entry> 
         <!-- 用户可以在这里配置自己的扩展停用词字典    -->
        <entry key="ext_stopwords">dicdata/ext_stopword.dic</entry> 
    
    </properties> 

      如果想配置扩展词和停用词,就创建扩展词的文件和停用词的文件,文件的编码要是utf-8

      注意不要用记事本保存扩展词文件和停用词文件那样的话格式中是含有bom。(使用IDE或者Editplus)

      添加扩展词文件:ext.dic,内容如下

      

  • 相关阅读:
    Windows Live Writer Testing
    基于本地文件系统的LocalDB
    【笔记】动画显示窗体
    winform无边框窗口拖动
    关于js的内存机制
    flex-basis
    Cookie、session和localStorage、以及sessionStorage之间的区别
    关于报文
    关于http与https Tcp的三次握手四次握手
    关于前后端分离与不分离
  • 原文地址:https://www.cnblogs.com/jiangbei/p/7485185.html
Copyright © 2020-2023  润新知