Skip to content

Commit a563e1f

Browse files
author
yangjingjing
committed
init blog
1 parent e2e8f71 commit a563e1f

30 files changed

+4161
-388
lines changed

.idea/checkstyle-idea.xml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_posts/2014-03-13-Gradle初探.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
layout: post
3+
categories: Maven
4+
description: none
5+
keywords: Maven
6+
---
7+
# Gradle初探
8+

_posts/2016-03-01-Tomcat简介.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ Tomcat 是 Apache 软件基金会(Apache Software Foundation)的 Jakarta 项
1111

1212
# 参考资料
1313

14+
Tomcat内核设计剖析
15+
1416
Tomcat 官网 [http://tomcat.apache.org/](http://tomcat.apache.org/)
1517
Tomcat9 下载地址[http://tomcat.apache.org/download-90.cgi](http://tomcat.apache.org/download-90.cgi)
Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ categories: Lucene
44
description: none
55
keywords: Lucene
66
---
7-
# Lucene简介
8-
Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。
7+
# Lucene入门简介
8+
Lucene是apache软件基金会jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。
9+
910
Lucene 是一个基于 Java 的全文信息检索工具包,目前主流的搜索系统Elasticsearch和solr都是基于lucene的索引和搜索能力进行。想要理解搜索系统的实现原理,就需要深入lucene这一层,看看lucene是如何存储需要检索的数据,以及如何完成高效的数据检索。
1011

1112
本文具体会分以下几部分:
@@ -72,18 +73,27 @@ Lucene中包含了四种基本数据类型,分别是:
7273

7374
## 基本概念
7475
在深入解读Lucene之前,先了解下Lucene的几个基本概念,以及这几个概念背后隐藏的一些东西。
76+
7577
### Index(索引)
7678
类似数据库的表的概念,但是与传统表的概念会有很大的不同。传统关系型数据库或者NoSQL数据库的表,在创建时至少要定义表的Scheme,定义表的主键或列等,会有一些明确定义的约束。而Lucene的Index,则完全没有约束。Lucene的Index可以理解为一个文档收纳箱,你可以往内部塞入新的文档,或者从里面拿出文档,但如果你要修改里面的某个文档,则必须先拿出来修改后再塞回去。这个收纳箱可以塞入各种类型的文档,文档里的内容可以任意定义,Lucene都能对其进行索引。
77-
### Document(文档)
78-
类似数据库内的行或者文档数据库内的文档的概念,一个Index内会包含多个Document。写入Index的Document会被分配一个唯一的ID,即Sequence Number(更多被叫做DocId),关于Sequence Number后面会再细说。
79+
80+
### Document(文档)
81+
索引和搜索时使用的主要数据载体,包含一个或多个存有数据的字段。类似数据库内的行或者文档数据库内的文档的概念,一个Index内会包含多个Document。写入Index的Document会被分配一个唯一的ID,即Sequence Number(更多被叫做DocId)。
82+
7983
### Field(字段)
80-
一个Document会由一个或多个Field组成,Field是Lucene中数据索引的最小定义单位。Lucene提供多种不同类型的Field,例如StringField、TextField、LongFiled或NumericDocValuesField等,Lucene根据Field的类型(FieldType)来判断该数据要采用哪种类型的索引方式(Invert Index、Store Field、DocValues或N-dimensional等),关于Field和FieldType后面会再细说。
81-
### Term和Term Dictionary
84+
文档的一部分,包含名称和值两部分。一个Document会由一个或多个Field组成,Field是Lucene中数据索引的最小定义单位。Lucene提供多种不同类型的Field,例如StringField、TextField、LongFiled或NumericDocValuesField等,Lucene根据Field的类型(FieldType)来判断该数据要采用哪种类型的索引方式(Invert Index、Store Field、DocValues或N-dimensional等),关于Field和FieldType后面会再细说。
85+
86+
### Term(词)和Term Dictionary
8287
Lucene中索引和搜索的最小单位,一个Field会由一个或多个Term组成,Term是由Field经过Analyzer(分词)产生。Term Dictionary即Term词典,是根据条件查找Term的基本索引。
88+
89+
### 标记 (token)
90+
表示在字段文本中出现的词,由这个词的文本、开始和结束偏移量以及类型组成。
91+
8392
### Segment
8493
一个Index会由一个或多个sub-index构成,sub-index被称为Segment。Lucene的Segment设计思想,与LSM类似但又有些不同,继承了LSM中数据写入的优点,但是在查询上只能提供近实时而非实时查询。
8594
Lucene中的数据写入会先写内存的一个Buffer(类似LSM的MemTable,但是不可读),当Buffer内数据到一定量后会被flush成一个Segment,每个Segment有自己独立的索引,可独立被查询,但数据永远不能被更改。这种模式避免了随机写,数据写入都是Batch和Append,能达到很高的吞吐量。Segment中写入的文档不可被修改,但可被删除,删除的方式也不是在文件内部原地更改,而是会由另外一个文件保存需要被删除的文档的DocID,保证数据文件不可被修改。Index的查询需要对多个Segment进行查询并对结果进行合并,还需要处理被删除的文档,为了对查询进行优化,Lucene会有策略对多个Segment进行合并,这点与LSM对SSTable的Merge类似。
8695
Segment在被flush或commit之前,数据保存在内存中,是不可被搜索的,这也就是为什么Lucene被称为提供近实时而非实时查询的原因。读了它的代码后,发现它并不是不能实现数据写入即可查,只是实现起来比较复杂。原因是Lucene中数据搜索依赖构建的索引(例如倒排依赖Term Dictionary),Lucene中对数据索引的构建会在Segment flush时,而非实时构建,目的是为了构建最高效索引。当然它可引入另外一套索引机制,在数据实时写入时即构建,但这套索引实现会与当前Segment内索引不同,需要引入额外的写入时索引以及另外一套查询机制,有一定复杂度。
96+
8797
### Sequence Number
8898
Sequence Number(后面统一叫DocId)是Lucene中一个很重要的概念,数据库内通过主键来唯一标识一行,而Lucene的Index通过DocId来唯一标识一个Doc。不过有几点要特别注意:
8999
DocId实际上并不在Index内唯一,而是Segment内唯一,Lucene这么做主要是为了做写入和压缩优化。那既然在Segment内才唯一,又是怎么做到在Index级别来唯一标识一个Doc呢?方案很简单,Segment之间是有顺序的,举个简单的例子,一个Index内有两个Segment,每个Segment内分别有100个Doc,在Segment内DocId都是0-100,转换到Index级的DocId,需要将第二个Segment的DocId范围转换为100-200。
@@ -92,10 +102,34 @@ DocId在Segment内唯一,取值从0开始递增。但不代表DocId取值一
92102
Lucene内最核心的倒排索引,本质上就是Term到所有包含该Term的文档的DocId列表的映射。所以Lucene内部在搜索的时候会是一个两阶段的查询,第一阶段是通过给定的Term的条件找到所有Doc的DocId列表,第二阶段是根据DocId查找Doc。Lucene提供基于Term的搜索功能,也提供基于DocId的查询功能。
93103
DocId采用一个从0开始底层的Int32值,是一个比较大的优化,同时体现在数据压缩和查询效率上。例如数据压缩上的Delta策略、ZigZag编码,以及倒排列表上采用的SkipList等,这些优化后续会详述。
94104

105+
## 输入数据分析
106+
当然,问题是,传入文档中的数据怎样转化成倒排索引,查询文本怎样变成可被搜索的词?这个数据转化的过程被称为**分析**
107+
108+
分析的工作由分析器 完成,它由一个分词器 (tokenizer)和零个或多个标记过滤器 (token filter)组成,也可以有零个或多个字符映射器 (character mapper)。
109+
110+
Lucene中的分词器把文本分割成多个标记,基本就是词加上一些额外信息,比如该词在原始文本中的位置和长度。分词器的处理结果称为标记流 (token stream),它是一个接一个的标记,准备被过滤器处理。
111+
112+
除了分词器,Lucene分析器包含零个或多个标记过滤器,用来处理标记流中的标记。下面是一些过滤器的例子。
113+
- 小写过滤器 (lowercase filter):把所有的标记变成小写。
114+
- 同义词过滤器 (synonyms filter):基于基本的同义词规则,把一个标记换成另一个同义的标记。
115+
- 多语言词干提取过滤器 (multiple language stemming filter):减少标记(实际上是标记中的文本部分),得到词根或者基本形式,即词干。
116+
117+
过滤器是一个接一个处理的。所以我们通过使用多个过滤器,几乎可以达到无限的分析可能性。
118+
119+
最后,字符映射器对未经分析的文本起作用,它们在分词器之前工作。因此,我们可以很容易地从文本的整体部分去除HTML标签而无需担心它们被标记。
120+
121+
## 索引和查询
122+
建立索引时,Lucene会使用你选择的分析器来处理你的文档内容。当然,不同的字段可以使用不同的分析器,所以文档的名称字段可以和汇总字段做不同的分析。如果我们愿意,也可以不分析字段。
123+
124+
索引应该和查询词匹配。如果它们不匹配,Lucene不会返回所需文档。比如,你在建立索引时使用了词干提取和小写,那你应该保证查询中的词也必须是词干和小写,否则你的查询不会返回任何结果。重要的是在索引和查询分析时,对所用标记过滤器保持相同的顺序,这样被分析出来的词是一样的。
125+
126+
## 评分和查询相关性
127+
什么是文档的得分?得分 是根据文档和查询的匹配度用计分公式计算的结果。默认情况下,Apache Lucene使用TF/IDF (term frequency/inverse document frequency,词频/逆向文档频率)评分机制,这是一种计算文档在我们查询上下文中相关度的算法。
128+
95129

96130
## Lucene实战
97131
Maven依赖
98-
```java
132+
```xml
99133
<dependencies>
100134
<dependency>
101135
<groupId>org.apache.lucene</groupId>

0 commit comments

Comments
 (0)