ElasticSearch 2 (24) - 语言处理系列之停用词:性能与精度
ElasticSearch 2 (24) - 语言处理系列之停用词:性能与精度
摘要
在信息检索早期,磁盘和内存相较我们今天的使用只是很小的一部分。将索引空间保持在一个较小的水平是至关重要的,节省每个字节都意味着巨大的性能提升。词干提取(参见 缩减单词至词根形式(Reducing Words to Their Root Form))的重要性不仅是因为它让搜索的内容更广泛、让检索的能力更深入,还因为它是压缩索引空间的工具。
要减少索引空间的另一个简单的方法就是索引更少的词。在搜索中,有些词要比其他词更重要,只索引那些更重要的词来可以大大减少索引的空间。
那么哪些词该被忽略呢?我可以粗略的将它们分为两类:
低频词(Low-frequency terms)
在文档集合中相对出现较少的词,因为它们稀少,所以它们的权重值更高。
高频词(High-frequency terms)
在索引下的文档集合中出现较多的常用词,比如
the
、and
和is
。这些词的权重小,对相关度评分影响不大。
小贴士
当然,频率实际上是个可以衡量的标尺而不是非 高 即 低 的标签。我们可以在标尺的任何位置选取一个标准,低于这个标准的属于低频词,高于它的属于高频词。
词项到底是低频或是高频取决于它们所处的文档。单词 and
如果在所有都是中文的文档里可能是个低频词。在关于数据库的文档集合里,单词 database
可能是一个高频词项,它对搜索这个特定集合毫无帮助。
每种语言都存在一些非常常见的单词,它们对搜索没有太大价值。在 Elasticsearch 中,英语默认的听用词为:
a, an, and, are, as, at, be, but, by, for, if, in, into, is, it,
no, not, of, on, or, such, that, the, their, then, there, these,
they, this, to, was, will, with
这些 停用词 通常在索引前就可以被过滤掉,对检索丝毫没有负面影响。但这真的是个好主意吗?
版本
elasticsearch版本: elasticsearch-2.x
内容
停用词的两面(Pros and Cons of Stopwords)
与过去相比,我们现在有更多的磁盘空间,更多的内存空间,更好的压缩算法。将之前的 33 个常见词从索引中移除,每百万文档只能节省 4MB 空间。为了索引空间移除停用词不再是个好的理由。(但这句话有个反例,我们会在 停用词与短语查询(Stopwords and Phrase Queries) 讨论)
在此基础上,从索引里将这些词移除会使我们降低某种类型的搜索能力。将前面这些所列单词移除会让我们难以完成以下事情:
- 区分 happy 和 not happy (高兴 和 不高兴)。
- 搜索 the 的连用 The The(注:类似 the more the better 这种连用)。
- 查找莎士比亚的名句 “To be, or not to be” (生存还是毁灭)。
- 使用挪威的国家代码:
no
。
移除停用词的最主要好处是性能,假设我们在个具有上百万文档的索引中搜索单词 fox
。或许 fox
只在其中 20 个文档中出现,也就是说 Elasticsearch 需要计算 20 个文档的相关度评分 _score
从而排出前十。现在我们把搜索条件改为 the OR fox
,几乎所有的文件都包含这个词,也就是说 Elasticsearch 需要为所有一百万文档计算评分 _score
。第二个查询肯定没有第一个的结果好。
幸运的是,我们有能让常用词查出来的技术,同时也维持较好的性能。首先,我们从如何使用停用词开始谈起。
停用词的使用(Using Stopwords)
移除停用词的工作是由 stop
停用词标记过滤器完成的,可以通过创建自定义的分析器来使用它(参见 使用停用词标记分析器(Using the stop Token Filter))。但是,也有一些自带的分析器预置使用停用词标记分析器:
语言分析器(Language analyzers)
每个语言分析器默认使用与该语言相适的停用词列表。例如,
english
英语分析器使用_english_
停用词列表。standard
标准分析器(standard
analyzer)默认使用空的停用词列表:
_none_
,实际上是禁用了停用词。pattern
模式分析器(pattern
analyzer)默认使用空的停用词列表:
_none_
,与standard
标准分析器一样。
停用词和标准分析器(Stopwords and the Standard Analyzer)
为了让标准分析器能与自定义停用词表连用,我们要做的只需创建一个分析器的配置好的版本,然后将停用词列表传入:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": { #1
"type": "standard", #2
"stopwords": [ "and", "the" ] #3
}
}
}
}
}
#1 自定义分析器,名字为 my_analyzer
。
#2 这个分析器是一个标准分析器,进行了一些自定义配置。
#3 停用词过滤了 and
和 the
。
小贴士
相同的技术也可以被应用于为任何语言分析器进行自定义配置。
保持位置(Maintaining Positions)
analyze
API 的输出十分有意思:
GET /my_index/_analyze?analyzer=my_analyzer
The quick and the dead
{
"tokens": [
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 2 #1
},
{
"token": "dead",
"start_offset": 18,
"end_offset": 22,
"type": "<ALPHANUM>",
"position": 5 #2
}
]
}
#1 #2 注意每个标记的位置 position
。
停用词如我们期望被过滤掉了,但有趣的是两个词项的位置 position
没有变化:quick
是原句子的第二个词,dead
是第五个。这对短语查询十分重要,因为如果每个词项的位置被调整了,一个短语查询 quick dead
会与以上示例中的文档错误匹配。
指定停用词(Specifying Stopwords)
停用词可以以内联的方式传入,就像我们前面示例一样,为它指定一个数组:
"stopwords": [ "and", "the" ]
为特定语言指定默认的停用词列表可以通过 _lang_
符号声明:
"stopwords": "_english_"
小贴士
Elasticsearch 中预定义的与语言相关的停用词列表可以在文档 停用词过滤器(stop token filter) 中找到。
停用词可以通过指定一个特殊列表 _none_
来禁用。例如,使用 english
分析器而不使用停用词,可以通过以下方式做到:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_english": {
"type": "english", #1
"stopwords": "_none_" #2
}
}
}
}
}
#1 my_english
分析器是基于 english
分析器的。
#2 但是停用词被禁用了。
最后,关键词也可以使用文件,只要文件中的每个词一行。这个文件必须存于集群中的每个节点,通过参数 stopwords_path
指定读取路径:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_english": {
"type": "english",
"stopwords_path": "stopwords/english.txt"
}
}
}
}
}
#1 停用词文件的路径,与 Elasticsearch 配置文件路径相对
使用停用词标记过滤器(Using the stop Token Filter)
停用词标记过滤器可以与标记器和其他标记过滤器联用,只要我们创建自定义分析器。例如,我们想创建一个下面这样的西班牙语分析器:
- 一个自定义停用词表
light_spanish
词干提取器asciifolding
过滤器用以移除变音符号
我们可以通过以下设置完成:
PUT /my_index
{
"settings": {
"analysis": {
"filter": {
"spanish_stop": {
"type": "stop",
"stopwords": [ "si", "esta", "el", "la" ] #1
},
"light_spanish": { #2
"type": "stemmer",
"language": "light_spanish"
}
},
"analyzer": {
"my_spanish": {
"tokenizer": "spanish",
"filter": [ #3
"lowercase",
"asciifolding",
"spanish_stop",
"light_spanish"
]
}
}
}
}
}
#1 与标准分析器一样,停用词标记过滤器同时接收参数 stopwords
和 stopwords_path
。
#2 参见 算法提取器(Algorithmic Stemmers)。
#3 标记过滤器的顺序非常重要,下面会进行解释。
我将 spanish_stop
过滤器置于 asciifolding
过滤器之后,这就意味着 esta
、ésta
和 está
会首先移除变音符号,变成 esta
,再以停用词被移除。但如果我们只想移除 esta
和 ésta
并保留 está
,我们就应该将 spanish_stop
放在 asciifolding
过滤器之前,然后在停用词表中同时指定两者。
更新停用词(Updating Stopwords)
想要更新分析器的停用词列表有多种方式,分析器是在索引创建时初始化的,也可以是在节点重启或重新开启一个已关闭索引时。
如果我们使用 stopwords
参数以内联方式指定停用词,我们只能通过关闭索引,用 API 更新分析器配置,最后再开启索引这样的方式完成更新停用词。
如果以 stopwords_path
参数的方式使用文件里的停用词,更新会较为容易。我们可以只更新每个节点上的文件,然后通过以下步骤重新强制创建分析器:
关闭和重开索引(参见 索引的开与关(open/close index))
一一重启集群下的每个节点。
当然,更新停用词表并不能改变已索引文档的状态。它只会应用于搜索和新建或更新的文档。为了改变已有文档,我们需要重新索引数据。参见 重新索引数据(Reindexing Your Data)。
停用词及其性能(Stopwords and Performance)
保留停用词最大的缺点就是它会影响性能。当 Elasticsearch 进行全文搜索时,它需要为所有匹配的文档计算相关度评分 _score
从而返回最匹配的前 10 个文档。
通常大多数词在所有文档出现的概率不超过 0.1%,有些词(如 the
)可能会在几乎所有文档出现,假设我们的索引中有一百万个文档,查询 quick brown fox
的匹配文档可能少于 1,000 个,而查询 the quick brown fox
则需要对几乎一百万个文档进行评分和排序,只是为了返回前 10 名最相关的文档!
问题在于 the quick brown fox
实际上是在查询 the OR quick OR brown OR fox
,任何文档即使它什么内容都没有而只包含 the
这个词也会被包括在结果集中。因此,我们需要找到一种降低待评分文档数量的方法。
and 操作符(and Operator)
我们想要减少带评分文档的数量,最简单的方式就是在匹配查询时使用 and
操作符,这样可以让所有词都是必须的。
一个 match
查询如下:
{
"match": {
"text": {
"query": "the quick brown fox",
"operator": "and"
}
}
}
它被重写成 bool
查询如下:
{
"bool": {
"must": [
{ "term": { "text": "the" }},
{ "term": { "text": "quick" }},
{ "term": { "text": "brown" }},
{ "term": { "text": "fox" }}
]
}
}
bool
查询会智能的根据较优的顺序依次执行每个 term
查询:它会从最低频的词开始。因为所有词项都必须匹配,只要包含低频词的文档才有可能匹配。使用 and
操作符可以大大提升多词查询的速度。
最少匹配数(minimum_should_match)
在 控制精度(Controlling Precision) 中,我们讨论过使用 minimum_should_match
操作符去掉结果中次相关的长尾。虽然它只对这个目的奏效,但是也为我们从侧面带来一个好处,它可以提供与 and
操作符相似的性能:
{
"match": {
"text": {
"query": "the quick brown fox",
"minimum_should_match": "75%"
}
}
}
在上面这个示例中,四分之三的词都必须匹配,这意味着我们只需考虑那些包含最低频或次低频词的文档。
相比默认使用 or
操作符的简单查询,这为我们带来了巨大的性能提升。不过我们有办法可以做得更好……
分而治之(Divide and Conquer)
查询字符串中的词项可以被划分成 更重要的(低频)和 次重要的(高频)这两类。只与次重要词项匹配的文档很有可能不太相关。实际上,我们想要文档能尽可能多的匹配那些更重要的词项。
match
查询接受一个参数 cutoff_frequency
,从而可以让它将查询字符串里的词项分为低频和高频两组。低频组(更重要的词项)组成 bulk
大量查询条件,而高频组(次重要的词项)只会用来评分,而不参与匹配过程。通过对这两组词的区分处理,我们可以在之前慢查询的基础上获得巨大的速度提升。
领域相关的停用词(Domain-Specific Stopwords)
cutoff_frequency
是我们使用 领域相关 停用词所带来的一个免费收益。例如,一个关于电影(movies)的网站可能会使用 movie(电影)、color(色彩)、black(黑) 和 white(白) 这些我们认为几乎没有意义的词。通过使用停用词标记过滤器,这些领域相关的词会被手工加入到停用词表中,但是,由于cutoff_frequency
会查看索引里词项的具体频率,这些词会被自动识别成 高频(high frequency)。
以下面查询为例:
{
"match": {
"text": {
"query": "Quick and the dead",
"cutoff_frequency": 0.01 #1
}
}
#1 任意词项只要它在文档从出现的频率超过 1% ,我们就认为它是高频词。cutoff_frequency
可以被指定一个小数(0.01
表示百分比)或一个绝对的数字(5
)。
查询首先用 cutoff_frequency
将词项分为 低频组(quick
、dead
)和高频组(and
、the
)。然后,查询被重写成以下形式的 bool
查询:
{
"bool": {
"must": { #1
"bool": {
"should": [
{ "term": { "text": "quick" }},
{ "term": { "text": "dead" }}
]
}
},
"should": { #2
"bool": {
"should": [
{ "term": { "text": "and" }},
{ "term": { "text": "the" }}
]
}
}
}
}
#1 至少一个低频/重要词 必须 匹配。
#2 高频/次重要词是非必须的。
must
语句的意思是至少有一个低频词(quick
或 dead
) 必须 出现在被匹配文档中,其他的所有文档都会被排除。should
语句会查找高频词 and
和 the
,但也只限于能与 must
语句匹配的集合中。should
语句的唯一工作就是在对如 “Quick and the dead” 和 “The quick but dead” 语句进行评分时,前者得分比后者高。这种方式可以大大减少需要进行评分计算的文档数量。
小贴士
将操作符参数设置成
and
会要求所有低频词都必须匹配,同时对包含所有高频词的文档给予更高评分。但是,在匹配文档时,并不要求文档必须包含所有高频词,如果希望文档包含所有的低频和高频词,我们应该使用一个bool
来替代。正如我们在 and 操作符(and Operator) 中看到的,它的查询效率已经很高了。
控制精度(Controlling Precision)
minimum_should_match
参数可以与 cutoff_frequency
结合使用,但是它只能应用于低频词。如下:
{
"match": {
"text": {
"query": "Quick and the dead",
"cutoff_frequency": 0.01,
"minimum_should_match": "75%"
}
}
被重写为:
{
"bool": {
"must": {
"bool": {
"should": [
{ "term": { "text": "quick" }},
{ "term": { "text": "dead" }}
],
"minimum_should_match": 1 #1
}
},
"should": { #2
"bool": {
"should": [
{ "term": { "text": "and" }},
{ "term": { "text": "the" }}
]
}
}
}
}
#1 因为这里只有两个词项,原来 75% 的比例会被取整为 1,即必须匹配低频词的两者之一。
#2 高频词仍然是可选的,只在评分时使用。
只有高频词(Only High-Frequency Terms)
当使用 or
查询仅对高频词(如:“To be, or not to be”)进行查询时性能最差。只是为了返回最匹配的前十个结果就对只是包含这些词的所有文档进行评分是盲目的。我们感兴趣的只是那些所有词都同时出现的文档,所以在这种情况下,低频词并不存在,重写后查询要求所有高频词都必须匹配:
{
"bool": {
"must": [
{ "term": { "text": "to" }},
{ "term": { "text": "be" }},
{ "term": { "text": "or" }},
{ "term": { "text": "not" }},
{ "term": { "text": "to" }},
{ "term": { "text": "be" }}
]
}
}
对常用词使用更多控制(More Control with Common Terms)
尽管高频/低频的功能在 match
查询中是有用的,有时我们还希望能对它有更多的控制,想控制它对高频和低频词分组的行为。match
查询针对 common
词项查询提供了一组功能。
例如,我们可以让所有低频词都必须匹配,而只对那些包括超过 75% 的高频词文档进行评分:
{
"common": {
"text": {
"query": "Quick and the dead",
"cutoff_frequency": 0.01,
"low_freq_operator": "and",
"minimum_should_match": {
"high_freq": "75%"
}
}
}
}
更多配置项参见 common
词项查询(common
terms query)。
停用词与短语查询(Stopwords and Phrase Queries)
在所有查询中,5% 的查询是短语查询(参见 短语查询(Phrase Matching)),它们通常也是慢查询的最大贡献者。短语查询可能性能非常差,特别是当短语包括常用词的时候,如 “To be, or not to be” 被认为是相当不正常的。原因在于必须支持近似匹配的数据量。
在 停用词的两面(Pros and Cons of Stopwords) 中,我们提到移除停用词只能节省倒排索引中的一小部分空间。这句话只部分正确,一个典型的索引会可能包含部分或所有以下数据:
词项字典(Terms dictionary)
索引中所有文档内所有词项的有序列表,以及包含该词的文档数量。
倒排表(Postings list)
包含每个词项的文档(ID)列表。
词频(Term frequency)
每个词项在每个文档里出现的频率。
位置(Positions)
每个词项在每个文档里出现的位置,供短语查询或近似查询使用。
偏移(Offsets)
每个词项在每个文档里开始与结束字符的偏移,供词语高亮使用,默认是禁用的。
规范因子(Norms)
用来对字段长度进行规范化处理的因子,给较短字段予以更多权重。
将停用词从索引中移除会节省 词项字典 和 倒排表 里的少量空间,但 位置 和 偏移 是另一码事。位置和偏移数据很容易变成索引大小的两倍、三倍、甚至四倍。
位置信息(Positions Data)
位置在 analyzed
字符串字段默认是开启的,所以短语查询能随时使用到它。词项出现的越频繁,用来存储它位置信息的空间就越多。在一个大的文档集合中,对于那些非常常见的词,它们的位置信息可能占用成百上千兆的空间。
运行一个针对高频词( the
)的短语查询可能会导致从磁盘读取好几G的数据。这些数据会被存储与文件系统的缓存核心中以提高后续访问的速度,这看似是件好事,但这可能会导致其他数据从缓存中被剔除,进一步使后续查询变慢。
这显然是我们需要解决的问题。
索引选项(Index Options)
我们首先应该问自己:到底是否需要短语查询还是近似查询?
答案通常是:不需要。在很多应用场景下,比如说日志,我们需要知道一个词是否在文档中,这个信息就在倒排表中。或许我们要对一两个字段使用短语查询,但是我们完全可以禁用其他 analyzed
字符串字段的位置信息。
index_options
参数允许我们控制索引里为每个字段存储的信息。可选值如下:
docs
只存储文档及其包含词项的信息。这对
not_analyzed
字符串字段是默认的。freqs
存储
docs
信息,以及每个词在每个文档里出现的频次。词频需要完整的 TF/IDF 相关度计算,但如果只想知道一个文档是否包含某个特定词项,则无需使用它。positions
存储
docs
和freqs
,以及每个词项在每个文档里出现的位置。这对analyzed
字符串字段是默认的,但当不需使用短语或近似匹配时,可以将其禁用。offsets
存储
docs
、freqs
、positions
,以及每个词在原始字符串中开始与结束字符的偏移信息。这个信息被用以高亮搜索结果,但它默认是禁用的。
我们可以在索引创建的时候为字段设置 index_options
选项,或者在使用 put-mapping
API 新增字段映射的时候设置。我们无法修改已有字段的这个设置。
PUT /my_index
{
"mappings": {
"my_type": {
"properties": {
"title": { #1
"type": "string"
},
"content": { #2
"type": "string",
"index_options": "freqs"
}
}
}
}
#1 title
字段使用默认的位置设置,所以它适于短语或近似查询。
#2 content
字段的位置设置是禁用的,所以它无法用于短语或近似查询。
停用词(Stopwords)
删除停用词是能使位置信息所占空间大大降低的一种方式。一个被删除停用词的索引仍然可以被用以短语查询,因为剩下的词的原始位置仍然被保存着,这正如 保持位置(Maintaining Positions) 中看见的那样。尽管如此,将词项从索引中排除终究会降低搜索能力,这使我们难以区分 Man in the moon 与 Man on the moon 这两个短语。
幸运的是,鱼与熊掌是可以兼得的:common_grams
标记过滤器。
common_grams 标记过滤器(common_grams Token Filter)
common_grams
标记过滤器是针对短语查询能更高效的使用停用词而设计的。它与 shingles
标记过滤器类似(参见 查找相关词(Finding Associated Words)),为每个相邻词对生成 bigrams。用示例解释更为容易。
common_grams
标记过滤器根据 query_mode 设置的不同而生成不同输出结果:false
(为索引使用) 或 true
(为搜索使用),所以我们必须创建两个独立的分析器:
PUT /my_index
{
"settings": {
"analysis": {
"filter": {
"index_filter": { #1
"type": "common_grams",
"common_words": "_english_" #2
},
"search_filter": { #3
"type": "common_grams",
"common_words": "_english_", #4
"query_mode": true
}
},
"analyzer": {
"index_grams": { #5
"tokenizer": "standard",
"filter": [ "lowercase", "index_filter" ]
},
"search_grams": { #6
"tokenizer": "standard",
"filter": [ "lowercase", "search_filter" ]
}
}
}
}
}
#1 #3 首先我们基于 common_grams
标记过滤器创建两个标记过滤器:index_filter
在索引时使用(此时 query_mode
的默认设置是 false
),search_filter
在查询时使用(此时 query_mode
的默认设置是 true
)。
#2 #4 common_words
参数可以接受与 stopwords
参数同样的选项(参见 指定停用词(Specifying Stopwords))。这个过滤器还可以接受参数 common_words_path
,使用存于文件里的常用词。
#5 #6 然后我们使用过滤器各创建一个索引时分析器和查询时分析器。
有了自定义分析器,我们可以创建一个字段在索引时使用 index_grams
分析器:
PUT /my_index/_mapping/my_type
{
"properties": {
"text": {
"type": "string",
"index_analyzer": "index_grams", #1
"search_analyzer": "standard" #2
}
}
}
#1 #2 text
字段索引时使用 index_grams
分析器,但是在搜索时默认使用 standard
分析器,稍后我们会解释其原因。
索引时(At Index Time)
如果我们对短语 quick and brown fox with shingles 进行分享,它会生成如下词项:
Pos 1: the_quick
Pos 2: quick_and
Pos 3: and_brown
Pos 4: brown_fox
新的 index_grams
分析器生成以下词项:
Pos 1: the, the_quick
Pos 2: quick, quick_and
Pos 3: and, and_brown
Pos 4: brown
Pos 5: fox
所有的词项都是以 unigrams 形式输出的(the
、quick
等等),但是如果一个词本身是常用词或者跟随着常用词,那么它同时还会在 unigram
同样的位置以 bigram
形式输出:the_quick
、quick_and
、and_brown
。
Unigram 查询(Unigram Queries)
因为索引包含 unigrams ,可以使用与其他字段相同的技术进行查询,例如:
GET /my_index/_search
{
"query": {
"match": {
"text": {
"query": "the quick and brown fox",
"cutoff_frequency": 0.01
}
}
}
}
上面这个查询字符串是通过为文本字段配置的 search_analyzer
分析器(本例中使用的是标准分析器)进行分析的, 它生成的词项为:the
、quick
、and
、brown
和 fox
。
因为文本字段的索引中包含与标准分析去生成的一样的 unigrams,搜索对于任何普通字段都能正常工作。
Bigram 短语查询(Bigram Phrase Queries)
但是当我们使用短语查询时,我们可以用专门的 search_grams
分析器让整个过程变得更高效:
GET /my_index/_search
{
"query": {
"match_phrase": {
"text": {
"query": "The quick and brown fox",
"analyzer": "search_grams" #1
}
}
}
}
#1 对于短语查询,我们重写了默认的 search_analyzer
分析器,而使用 search_grams
分析器。
search_grams
分析器会生成以下词项:
Pos 1: the_quick
Pos 2: quick_and
Pos 3: and_brown
Pos 4: brown
Pos 5: fox
分析器剔除了所有常用词的 unigrams,只留下常用词的 bigrams 以及低频的 unigrams。如 the_quick
这样的 bigrams
比单个词项 the
更为少见,这样有两个好处:
the_quick
的位置信息要比the
的小得多,所以它读取磁盘更快,对系统缓存的影响也更小。词项
the_quick
没有the
那么常见,所以它可以大量减少需要计算的文档。
两词短语(Two-Word Phrases)
There is one further optimization. By far the majority of phrase queries consist of only two words. If one of those words happens to be a common word, such as
我们的优化可以更进一步,因为大多数的短语查询只由两个词组成,如果其中一个恰好又是常用词,例如:
GET /my_index/_search
{
"query": {
"match_phrase": {
"text": {
"query": "The quick",
"analyzer": "search_grams"
}
}
}
}
那么 search_grams
分析器会输出单个标记:the_quick
。这将原来昂贵的查询(查询 the
和 quick
)转换成了对单个词项的高效查找。
停用词与相关性(Stopwords and Relevance)
在离开停用词相关内容之前,最后一个话题是关于相关性的。在索引中保留停用词会降低相关度计算的准确性,特别是当我们的文档非常长时。
正如我们已经在 词频饱和度(Term-frequency saturation) 中讨论过的,原因在于 TF/IDF 没有为词频的影响设置上限,非常常用的词可能由于文档的长度很长,而降低它们的重要性,停用词如果在单个文档中的出现频率陡增,也可能导致他们的权重值被人为刺激而变大。
可能也会考虑对较长字段使用 Okapi BM25 相似度算法,并且包括使用停用词,而不是默认的 Lucene 相似度。
参考
elastic.co: Stopwords: Performance Versus Precision
ElasticSearch 2 (24) - 语言处理系列之停用词:性能与精度的更多相关文章
- ElasticSearch 2 (25) - 语言处理系列之同义词
ElasticSearch 2 (25) - 语言处理系列之同义词 摘要 词干提取有助于通过简化屈折词到它们词根的形式来扩展搜索的范围,而同义词是通过关联概念和想法来扩展搜索范围的.或许没有文档能与查 ...
- ElasticSearch 2 (23) - 语言处理系列之词根提取
ElasticSearch 2 (23) - 语言处理系列之词根提取 摘要 世界上大多数语言都是屈折变化的,意思是词语可以通过变形来表达不同的含义: 数(Number): fox, foxes 时态( ...
- ElasticSearch 2 (21) - 语言处理系列之单词识别
ElasticSearch 2 (21) - 语言处理系列之单词识别 摘要 一个英语单词相对容易识别:因为英语单词是被空格或(某些)标点符号隔开的.但在英语中也有反例:you're 这个词是一个单词还 ...
- ElasticSearch 2 (20) - 语言处理系列之如何开始
ElasticSearch 2 (20) - 语言处理系列之如何开始 摘要 Elasticsearch 配备了一组语言分析器,为世界上大多数常见的语言提供良好的现成基础支持. 阿拉伯语.亚美尼亚语,巴 ...
- ElasticSearch 2 (19) - 语言处理系列之故事开始
ElasticSearch 2 (19) - 语言处理系列之故事开始 摘要 全文搜索是精度(尽可能少的返回不相关文档)和召回(尽可能多的返回相关文档)的战场.尽管只精确匹配用户查询的词肯定会是精确的, ...
- ElasticSearch 2 (26) - 语言处理系列之打字或拼写错误
ElasticSearch 2 (26) - 语言处理系列之打字或拼写错误 摘要 我们喜欢在对结构化数据(如:日期和价格)做查询时,结果只返回那些能精确匹配的文档.但是,好的全文搜索不应该有这样的限制 ...
- ElasticSearch 2 (22) - 语言处理系列之标记规范化
ElasticSearch 2 (22) - 语言处理系列之标记规范化 摘要 将文本拆解成标记只是工作的一半.为了使这些标记更容易被搜索到,它们需要经过一个规范化的处理过程,以移除相同单词间不重要的差 ...
- Elasticsearch的停用词(stopwords)
1.问题 在使用搜索引擎(Elasticsearch或Solr)作为应用的后台搜索平台的时候,会遇到停用词(stopwords)的问题. 在信息检索中,停用词是为节省存储空间和提高搜索效率,处理文本时 ...
- ElasticSearch 2 (18) - 深入搜索系列之控制相关度
ElasticSearch 2 (18) - 深入搜索系列之控制相关度 摘要 处理结构化数据(比如:时间.数字.字符串.枚举)的数据库只需要检查一个文档(或行,在关系数据库)是否与查询匹配. 布尔是/ ...
随机推荐
- poi 创建excel数据
public static void main(String[] args) throws Exception { // TODO 设置excel的标题 List<String> exce ...
- Shell学习心得(二):传递参数、运算符
1.传递参数 可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… 向脚本传递三个参数, ...
- jmeter测试webservice接口
webservice怎样使用jmeter测试呢? 测试样例url=http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx ...
- Python2.7-Queue
Queue 模块,python3中为queue,一般和threading模块同时使用,用于处理多任务队列,模块定义了3种队列类,先进先出(FIFO),后进先出(LIFO),优先级队列 Queue.Qu ...
- Vue 下拉列表 组件模板
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Jmeter—实现识别验证码登录
在做自动化测试或压力测试时,验证码总是一个问题.在以往的压力测试经历中,测试一般在独立的测试环境中进行,可以放心禁用验证码或使用万能验证码,这个是最实用的.但是,这两天我尝试了一个使用第三方的图形图像 ...
- Loopback接口用途---用作管理地址。
Loopback接口的优点是永远不会down点,不管是链路断开还是网卡损坏.因而loopback接口有很高健壮性. 但是loopback并非实际网口,外部设备要与该口通信,必须经过实际口的路由实现. ...
- WPF bind baidu Image
as there baidu image has protect refer from other site to use. need download i use request header a ...
- 20155331 Exp3 免杀原理与实践
20155331 Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 1.基于特征码的检测,2.启发式恶意软件检测,3.基于行为的恶意软件检测. 免杀是做什么? 让病毒不被杀毒软件杀 ...
- 使用FindAncestor查找方式绑定且不需要使用datacontext
原文:使用FindAncestor查找方式绑定且不需要使用datacontext <UserControl x:Class="QuJiao.AnimationVideoPlayer&q ...