Lucene分词器

介绍

历史: 创始人Doug Cutting(hadoop);
lucene:是搜索引擎的工具包基于java编写的

特点

稳定,索引性能高(倒排索引)
现代硬盘每小时索引150G数据(索引:创建索引文件) java运行时要求的堆内存1MB
增量索引和批量索引一样快提供排名
支持多种主流的搜索功能:短语,通配符,模糊,近似,范围,此项,多 义词等查询功能

lucene的分词计算

分词:分词的过程就是将源数据中某段字符串根据人类使用语言的习惯进行词汇的切分.设计到语言不同,设计到语言的发展.

添加lucene的测试依赖

Lucene本身携带多种分词器,但是无法满足语言不同,语言发展的要求定义了Analyzer的接口,只要开发人员实现了这个接口就可以按照自定义的规则完成一些分词的计算,比如中文有很多分词器(分词器的jar包非常多)。

编写一个静态方法,利用传入的不同分词器对象,对同一个字符串进行分词计算,将分词结果打印进行对比

public class luceneTest {
    public static void printAnalyzer(Analyzer analyzer, String str) throws Exception {
        //将字符串传话成流对象String流
        StringReader reader = new StringReader(str);
        //analyzer底层实现,是通过tokenStream来完成的,根据实现的不同实现类中的tokenStream方法,对数据流进行分词,属性计算.
        TokenStream tokenStream = analyzer.tokenStream("test", reader);
        tokenStream.reset();//重置属性,从头开始
        //从分词token流中获取词项属性,词项:分词的每个最小意义的词,就是一个词项
        CharTermAttribute attribute
                = tokenStream.getAttribute(CharTermAttribute.class);
        //while循环获取所有的词项输出
        while (tokenStream.incrementToken()) {
            System.out.println(attribute.toString());
        }
    }

@Test
public void run() throws Exception {
    //准备lucene的不同分词器对象
    Analyzer a1 = new SmartChineseAnalyzer();//智能中文分词器
    Analyzer a2 = new WhitespaceAnalyzer();
    Analyzer a3 = new SimpleAnalyzer();

    String str = "我是你爸爸,你最近还好吗,我能和你见个面吗";
    System.out.println("智能分词器***********************");
    LucenTokenTest.printAnalyzer(a1, str);
    System.out.println("空格分词器***********************");
    LucenTokenTest.printAnalyzer(a2, str);
    System.out.println("简单分词器***********************");
    LucenTokenTest.printAnalyzer(a3, str);
  }
}

对于文本数据,进行分词切分的过程是非常关键的,能否有效,高效的查询到数据,在底层取决于分词计算的精准度的。

lucene创建索引

创建索引:创建索引是根据数据源读取的数据,进行整理, 完成倒排索引后输出成索引文件,只有数据库有数据源;根 据商品表格中的内容,完成当前需要的索引文件的创建;

索引创建中的一些概念

文档:检索结果的对象封装(数据单位),可以封装一个网 页内容,也可以封装一条商品的数据记录
查询:搜索条件的封装,在查询时有各种条件,限制,都可 以在查询对象中体现,最终实现利用查询对象完成复杂的搜 索逻辑
词项:分词计算结果的最小意义的词
域:就是文档对象的一个属性,根据封装的内容不同,域可 以变动;

/*
*使用lucene创建索引文件
*1 指定输出文件的位置,当前工程“index”文件夹
*2 设置索引创建时的配置对象,指定分词等环境信息
*3 手动创建保存的数据对象–document
*4 使用lucene的流,将数据输出(会计算数据的分词创建索引)
*/
@Test
public void createIndex() throws Exception {

    //指定文件夹
    Path path = Paths.get("index");
    //指定lucene格式的输出路径对象
    FSDirectory directory = FSDirectory.open(path);
    //生成配置对象,指定分词器
    Analyzer analyzer = new IKAnalyzer6x();
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    config.setOpenMode(OpenMode.CREATE);
    //create表示每次创建都覆盖,append每次创建都 追加
    //create_or_append 有就追加,没有就创建
    //生成存储的数据对象,doc1商品数据为例 
    doc2 Document doc1 = new Document();
    Document doc2 = new Document();
    //对文档对象进行数据的添加,需要使用到field(字段,属性)
    //name表示当前域的名称
    //value当前添加的域属性的值
    //Store.yes在创建索引文件时,document的这个域 值会不会存在索引文件里
    doc1.add(new StringField("id", "1000", Store.YES));
    doc1.add(new TextField("title", " 三星(SAMSUNG) 860 EVO 250G 2.5英寸 SATAIII 固态硬盘(MZ-76E250B)", Store.YES));
    doc1.add(new TextField("desc", "快,就是快,无比的快", Store.YES));

    //Store.yes和no的区别,StringField和TextField区 别
    doc2.add(new StringField("id", "100", Store.NO));
    doc2.add(new StringField("content", "我们今天是否要去晚餐", Store.NO));
    //数据来源需要读取数据,不是手动添加
    //输出到索引文件创建索引
    //在writer对document进行输出时,会根据配置的 分词器,进行数据的分词计算
    IndexWriter writer = new IndexWriter(directory, config);
    writer.addDocument(doc1);
    writer.addDocument(doc2);
    writer.commit();
    writer.close();
    directory.close();
}

对于新创建的索引文件,数据结构无法使用普通的软件打开 查看,需要利用专门的工具,LUKE工具6.0.0必须和lucene的代码版本完全一致(luke基于lucene开发编写的)

StringField和TextField的区别:

StringField不做分词计算;例如在某个商品的数据中,图片url 不需要分词计算,字符串的id(ksdah739klsdhsa932) TextField会做分词计算
以上2个域属性的类型,是对数据的处理类型;
其他的int long double这种类型的数据不会做索引存储

IntPoint LongPoint DoublePoint FloutPoint

只会在底层计算二进制后,完成搜索过程的筛选过滤,范围 查询等功能,不会存储在索引文件中
在数据中,有些属性只有数值的特性比如价钱
如果使用double,不会再索引文件中存储这个数据,但是可 以利用范围搜索将price的取值范围查询出来;
例如,price DoublePoint(“price”,56.88),范围搜索40<price<60,将会被查询到这个对象
如果需要对某个字段既能使用数字的查询功能,又需要存储 数据,利用StringField在存一个同名的域

Store.yes和no的区别

一个在document的索引数据对象中保存数据,一个是不保
存;在搜索时,搜索到的一批document结果集,如果域yes保 存,可以从结果集的对象中获取域的数据,no不保存,即使搜到这个document也无法获取域的值

lucene索引的查询

lucene搜索能力非常强大,根据分装的不同类型的查询条件对象Query,Query是一个查询条件的接口类,不同的查询结构,可以利用不同的实现类来完成条件的封装
词项查询多域查询布尔查询范围查询前缀查询
多关键字查询模糊查询
通配符查询等

查询入门

可以根据分词计算结果的词项,把收集的查询条件做成TermQuery,如果有词项并且对应指向了一批document将会把查询结果返回;拿到的数据结果就是documents(文档对象的集合)

/*
*lucene查询搜索的测试
*1 指定路径
*2 封装查询对象Query
*3 查询获取结果集
*4 从结果集封装业务需要的数据
*/

@Test
public void search() throws Exception {
    //路径指定
    Path path = Paths.get("index");
    FSDirectory directory = FSDirectory.open(path);
    //使用输入流打开索引文件
    IndexReader reader = DirectoryReader.open(directory);
    //获取查询对象
    IndexSearcher searcher = new IndexSearcher(reader);
    //指定一个查询时可能需要的分词器对象
    Analyzer analyzer = new IKAnalyzer6x();
    //封装查询query对象
    //name是域名称,针对哪个域进行搜索
    //a,analyzer分词器
    QueryParser parser = new QueryParser("title", analyzer);
    parser.setDefaultOperator(Operator.OR);
    //查询条件 中华人民共和国,利用分词器对查询字符串“中华人民共和国”分词
    //中华,华人,人民,共和国,Operator.AND表示查询条件的分词结果的词项必须同时
    //存在于一批document,才可以查询到结果
    Query query = parser.parse("三星英特尔");
    //查询数据,获取结果集
    TopDocs docs = searcher.search(query, 10);
    //从topdocs中获取每个document对象

    ScoreDoc[] scoreDocs = docs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        Document doc = searcher.doc(scoreDoc.doc);
        //获取doc中的数据
        System.out.println("id:" + doc.get("id"));
        System.out.println("title:" + doc.get("title"));
        System.out.println("desc:" + doc.get("desc"));
        System.out.println("文档评分:" + scoreDoc.score);
    }
}

多域查询
利用多个域的名称和数据,封装MutiFieldQuery 对象,利用这个查询对象进行数据的搜索; @Test

public void searchMuti() throws Exception {
    //路径指定
    Path path = Paths.get("index");
    FSDirectory directory = FSDirectory.open(path);
    //使用输入流打开索引文件
    IndexReader reader = DirectoryReader.open(directory);
    // 获 取 查 询 对 象 
    IndexSearcher searcher = new IndexSearcher(reader);
    //指定一个查询时可能需要的分词器对象
    Analyzer analyzer = new IKAnalyzer6x();
    //封装查询query对象,多域查询对象

    //多域的域名数组
    String[] fields = {"title", "content" };
    MultiFieldQueryParser parser =
            new MultiFieldQueryParser(fields, analyzer);
    Query query = parser.parse("三星");
    //查询数据,获取结果集
    TopDocs docs = searcher.search(query, 10);
    //从topdocs中获取每个document对象
    ScoreDoc[] scoreDocs = docs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        Document doc = searcher.doc(scoreDoc.doc);
    //获取doc中的数据
        System.out.println("id:" + doc.get("id"));
        System.out.println("title:" + doc.get("title"));
        System.out.println("desc:" + doc.get("desc"));
        System.out.println("content:" + doc.get("conten t"));
        System.out.println("webid:" + doc.get("webid"));
        System.out.println("文档评分:" + scoreDoc.score);
    }
}

词项查询
前面2个查询都是对查询条件的字符串进行了分词计算,词项查询条件,直接比对词项不可进行二次的分词计算;
TermQuery

    @Test
    public void searchTerm() throws Exception {
        //路径指定
        Path path = Paths.get("index");
        FSDirectory directory = FSDirectory.open(path);
        //使用输入流打开索引文件
        IndexReader reader = DirectoryReader.open(directory);
        // 获 取 查 询 对 象 
        IndexSearcher searcher = new IndexSearcher(reader);
        //指定一个查询时可能需要的分词器对象
        Analyzer analyzer = new IKAnalyzer6x();
        //封装查询query对象,多域查询对象
        //多域的域名数组
        Term term = new Term("title", "三星英特尔");
        Query query = new TermQuery(term);
        //查询数据,获取结果集
        TopDocs docs = searcher.search(query, 10);
        //从topdocs中获取每个document对象
        ScoreDoc[] scoreDocs = docs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            Document doc = searcher.doc(scoreDoc.doc);
            //获取doc中的数据
            System.out.println("id:" + doc.get("id"));
            System.out.println("title:" + doc.get("title"));
            System.out.println("desc:" + doc.get("desc"));
            System.out.println("content:" + doc.get("conten t"));
            System.out.println("webid:" + doc.get("webid"));
            System.out.println("文档评分:" + scoreDoc.score);
        }
    }
}

布尔查询

组合多种query的查询方式,并且言明中间结果的逻辑关系;

    @Test
    public void searchBoolean() throws Exception {
        //路径指定
        Path path = Paths.get("index");
        FSDirectory directory = FSDirectory.open(path);
        //使用输入流打开索引文件
        IndexReader reader = DirectoryReader.open(directory);
        // 获 取 查 询 对 象 
        IndexSearcher searcher = new IndexSearcher(reader);
        //指定一个查询时可能需要的分词器对象Analyzer analyzer=new IKAnalyzer6x();

    //封装查询query对象
    Term term01 = new Term("title", " 三 星 ");
    Query query01 = new TermQuery(term01);
    Term term02 = new Term("title", "英特尔");
    Query query02 = new TermQuery(term02);
    //创建布尔查询的条件和逻辑
    BooleanClause bc1 = new BooleanClause(query01, Occur.MUST);
    BooleanClause bc2 = new BooleanClause(query02, Occur.MUST_NOT);
    BooleanQuery query = new BooleanQuery.Builder().add(bc1).add(bc2).build();
    //查询数据,获取结果集
    TopDocs docs = searcher.search(query, 10);
    //从topdocs中获取每个document对象
    ScoreDoc[] scoreDocs = docs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        Document doc = searcher.doc(scoreDoc.doc);
        //获取doc中的数据
        System.out.println("id:" + doc.get("id"));
        System.out.println("title:" + doc.get("title"));
        System.out.println("desc:" + doc.get("desc"));
        System.out.println("content:" + doc.get("conten t"));
        System.out.println("webid:" + doc.get("webid"));
        System.out.println("文档评分:" + scoreDoc.score);
    }
}

范围查询

@Test
public void searchRange() throws Exception {
    //路径指定
    Path path = Paths.get("index");
    FSDirectory directory = FSDirectory.open(path);
    //使用输入流打开索引文件
    IndexReader reader = DirectoryReader.open(directory);
    // 获 取 查 询 对 象 
    IndexSearcher searcher = new IndexSearcher(reader);
    //指定一个查询时可能需要的分词器对象
    Analyzer analyzer = new IKAnalyzer6x();
    //封装查询query对象Query
    query = IntPoint.newRangeQuery("price", 4500, 6000);
    //查询数据,获取结果集
    TopDocs docs = searcher.search(query,

            10);
    //从topdocs中获取每个document对象
    ScoreDoc[] scoreDocs = docs.scoreDocs;
    for (ScoreDoc scoreDoc : scoreDocs) {
        Document doc = searcher.doc(scoreDoc.doc);
        //获取doc中的数据
        System.out.println("id:" + doc.get("id"));
        System.out.println("title:" + doc.get("title "));
        System.out.println("desc:" + doc.get("de sc"));
        System.out.println("content:" + doc.get(" content"));
        System.out.println("webid:" + doc.get("w ebid"));
        System.out.println("文档评分 :" + scoreDoc.score);
        System.out.println("price:" + doc.get("pri ce"));
    }
  }
}

前缀查询
PrefixQuery 前缀查询条件,需要先定义一个词项Term,表示当文档中的词项以这个term内容开始时,返回查询数 据;

Term term=new Term("title",“微型”)
Query query=new PrefixQuery(term)

查到所有用“微型”起始的内容,返回document结果集

多关键字查询
除了TermQuery外还有多个词项关键字查询的条件,常常查询都需要使用一句话,一个整个报错来搜索网站上曾经有的错误信息;需要各种各样的关键字在其中起作用;

PhraseQuery.Builder build=new PhraseQuery.Builder();
build.add(new Term("title",“ 黑 色 ”)); build.add(new Term("title",“英特尔”)) PhraseQuery query=build.build();

模糊查询
FuzzyQuery,可以识别简单的相近字,日和曰,trump和tramp,已经完成的底层算法,对不同的语言支持的能力有待验证;

Term term=new Term("name","tramp")
FuzzyQuery query=new FuzzyQuery(term)

通配符

WildcardQuery query=new WildcardQuery(new Term("name","不?"))

词项中不是,不能,不要,不可以(?匹配一个还是所有);

Lucene缺点

不支持分布式
只是底层代码实现的索引使用的逻辑,并不能完成海量数据整 理成索引后,对索引文件的分布式高可用管理;
在搜索系统中,保证系统逻辑的高可用是容易做到的;多搭建 几台搜索的应用服务器,但是数据层面,lucene无法完成分布式的输入和输出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Lucene 5.5是一个开源的Java搜索引擎库,用于文本分析、索引和搜索。在Lucene中,分词器(Tokenizer)是用于将输入文本按照特定规则切分成单词(token)的工具。 Lucene 5.5提供了多种分词器,常用的有标准分词器(StandardTokenizer)、简单分词器(SimpleAnalyzer)、关键字分词器(KeywordAnalyzer)等。这些分词器在应用场景和切分规则上有所不同,用户可以根据需求选择合适的分词器。 标准分词器Lucene中最常用的分词器之一,它通过去除空格、标点符号等特殊字符,将输入文本切分成一系列单词。这个过程叫做词法分析(tokenizing)。标准分词器还提供了一些附加的文本处理功能,例如将单词转换为小写(lowercasing)、去除停用词(stopwords)等。 简单分词器是一个基本的分词器,它将输入文本用空格切分成单词,并将单词转换为小写。这个分词器在某些简单的搜索场景中会有一定的使用价值。 关键字分词器则是将整个输入文本当作一个单词进行处理,适用于某些特殊的搜索需求。例如,当用户输入一个关键字作为搜索条件时,关键字分词器可以直接将整个关键字当作一个单词进行匹配。 除了以上提到的分词器Lucene还提供了其他各种特定场景下的分词器,例如CJK分词器适用于中日韩文本的分词,Whitespace分词器将输入文本按照空格进行切分等等。 总结来说,Lucene 5.5提供了多种分词器供用户选择,根据不同的文本分析需求和搜索场景,选择合适的分词器可以提高搜索的效果和准确性。 ### 回答2: Lucene 5.5 是一款开源的全文搜索引擎库,其中的分词器是其核心组件之一。分词器用于将输入的文本进行切分,生成词条列表,以便进行索引和搜索。 Lucene 5.5 提供了多种分词器,常用的有标准分词器(StandardAnalyzer)和中文智能分词器(SmartChineseAnalyzer)。 标准分词器是最常用的分词器之一,它基于语法规则对文本进行切分,以空格、标点符号等作为分隔符。它能够处理英文等非中文文本,但对于中文文本效果不佳,因为中文没有明确的分隔符。 中文智能分词器是专门针对中文文本设计的分词器,它不仅考虑了语法规则,还结合了汉字之间的概率关联关系对文本进行切分。通过对大量的中文语料进行训练,智能分词器可以较好地解决中文分词中的歧义性问题,提升分词的准确性和效果。 除了以上两种分词器Lucene 5.5 还提供了其他一些适用于特定场景的分词器,如关键字分词器(KeywordAnalyzer)和简单分词器(SimpleAnalyzer)。用户也可以根据自己的需求自定义分词器,通过实现接口来自定义词汇的切分规则。 总之,Lucene 5.5 分词器是一系列能够对文本进行切分的工具,包括了多种分词算法和规则,以满足不同场景下的需求。通过合理选择和应用分词器,可以提高全文搜索引擎的准确性和效率,为用户提供更好的搜索体验。 ### 回答3: Lucene 5.5 是一个开源的全文搜索引擎库,其中包含了许多功能强大的分词器。 在Lucene 5.5中,分词器是用于将文本分成单个的词语或词元的组件。这对于搜索引擎的索引构建和查询处理非常重要。在Lucene中,我们可以使用不同类型的分词器来满足不同的需求。 Lucene 5.5提供了许多内置的分词器。其中最常用的是StandardAnalyzer,它是基于标准英语规则的分词器,它可以将文本分成单词,并过滤掉一些常见的停用词。此外,还有KeywordAnalyzer,它将文本视为一个整体,不对其进行分词。另外还有SimpleAnalyzer,它将文本按照非字母字符进行分割,并将其小写化。还有WhitespaceAnalyzer,它将文本按照空格进行分割。 除了这些内置的分词器Lucene 5.5还支持自定义的分词器。开发人员可以根据自己的需求实现自己的分词器。自定义分词器需要实现TokenStream接口,该接口定义了文本分词后的词元流。 通过使用Lucene 5.5的分词器,我们可以将待搜索的文本分成单个的词语或词元,从而提高搜索的准确性和效率。分词器是搜索引擎中一个非常关键的组件,它的质量和性能直接影响着整个搜索过程的效果。因此,了解和选择适合的分词器是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值