ElasticSearch【有与无】【搜索引擎】【ES20】将单词还原为词根

目录

1.简介

1.1.词干提取算法(stemmer algorithm)

1.2.字典词干提取器

1.3.Hunspell 词干提取器

安装一个词典

创建一个 Hunspell 语汇单元过滤器

Hunspell 词典格式

1.4.选择一个词干提取器

提取性能

提取程度

选择

1.5.控制词干提取

阻止词干提取

自定义提取

原形词干提取


1.简介

大多数语言的单词都可以 词形变化,比如

  • 单复数变化 : fox 、foxes
  • 时态变化 : pay 、 paid 、 paying
  • 性别变化 : waiter 、 waitress
  • 动词人称变化 : hear 、 hears
  • 代词变化 : I 、 me 、 my
  • 不规则变化 : ate 、 eaten
  • 情景变化 : so be it 、 were it so

词干提取 试图移除单词的变化形式之间的差别,从而达到将每个词都提取为它的词根形式。 

词干提取是一种遭受两种困扰的模糊的技术:

  • 词干弱提取 : 无法将同样意思的单词缩减为同一个词根。弱词干提取会导致搜索时无法返回相关文档。
  • 词干过度提取 : 无法将不同含义的单词分开。词干过度提取会降低精准度:不相干的文档会在不需要返回的时候返回。
词形还原
原词是一组相关词的规范形式,或词典形式 — paying 、paid 和 pays 的原词是 pay 。
通常原词很像与其相关的词,但有时也不像 — is 、 was 、 am 和 being 的原词是 be 。

词形还原,很像词干提取,试图归类相关单词,但是它比词干提取先进一步的是它企图按单词的 词义 ,或意义归类。 
同样的单词可能表现出两种意思—例如, wake 可以表现为 to wake up 或 a funeral 。
然而词形还原试图区分两个词的词义,词干提取却会将其混为一谈。

词形还原是一种更复杂和高资源消耗的过程,它需要理解单词出现的上下文来决定词的意思。
实践中,词干提取似乎比词形还原更高效,且代价更低。

 

1.1.词干提取算法(stemmer algorithm)

提供了一系列规则用于将一个词提取为它的词根形式。

提取单词词干时并不需要知道该词的任何信息。

[优点]

可以作为插件使用,速度快,占用内存少,有规律的单词处理效果好

[缺点]

没规律的单词效果不好

【举例】

[激进]

{
  "settings": {
    "analysis": {
      "filter": {
        "english_stop": {
          "type":       "stop",
          "stopwords":  "_english_"
        },
        "english_keywords": {
          "type":       "keyword_marker",  // 分词过滤器列出那些不用被词干提取的单词。这个过滤器默认情况下是一个空的列表。
          "keywords":   []
        },
        "english_stemmer": {
          "type":       "stemmer",
          "language":   "english"  // 词干提取器,激进
        },
        "english_possessive_stemmer": {
          "type":       "stemmer",
          "language":   "possessive_english"  // 词干提取器
        }
      },
      "analyzer": {
        "english": {
          "tokenizer":  "standard",
          "filter": [
            "english_possessive_stemmer",
            "lowercase",
            "english_stop",
            "english_keywords",
            "english_stemmer"
          ]
        }
      }
    }
  }
}

[非激进]

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "english_stop": {
          "type":       "stop",
          "stopwords":  "_english_"
        },
        "light_english_stemmer": {
          "type":       "stemmer",
          "language":   "light_english"  // 词干提取器,非激进
        },
        "english_possessive_stemmer": {
          "type":       "stemmer",
          "language":   "possessive_english"
        }
      },
      "analyzer": {
        "english": {
          "tokenizer":  "standard",
          "filter": [
            "english_possessive_stemmer",
            "lowercase",
            "english_stop",
            "light_english_stemmer", 
            "asciifolding"  // 分词过滤器
          ]
        }
      }
    }
  }
}

 

1.2.字典词干提取器

字典词干提取器只是简单地在字典里查找词。理论上可以给出比算法化词干提取器更好的结果。

一个字典词干提取器应当可以

  • 返回不规则形式如 feet 和 mice 的正确词干
  • 区分出词形相似但词义不同的情形,比如 organ and organization

实践中一个好的算法化词干提取器一般优于一个字典词干提取器。应该有以下两大原因:

① 字典质量

一个字典词干提取器再好也就跟它的字典一样。 据牛津英语字典网站估计,英语包含大约75万个单词(包含变音变形词)。电脑上的大部分英语字典只包含其中的 10% 。

词的含义随时光变迁。mobility 提取词干 mobil 先前可能讲得通,但现在合并进了手机可移动性的含义。字典需要保持最新,这是一项很耗时的任务。通常等到一个字典变得好用后,其中的部分内容已经过时。

字典词干提取器对于字典中不存在的词无能为力。而一个基于算法的词干提取器,则会继续应用之前的相同规则,结果可能正确或错误。

② 大小与性能

字典词干提取器需要加载所有词汇、 所有前缀,以及所有后缀到内存中。这会显著地消耗内存。找到一个词的正确词干,一般比算法化词干提取器的相同过程更加复杂。

依赖于不同的字典质量,去除前后缀的过程可能会更加高效或低效。低效的情形可能会明显地拖慢整个词干提取过程。

另一方面,算法化词干提取器通常更简单、轻量和快速。

如果你所使用的语言有比较好的算法化词干提取器,这通常是比一个基于字典的词干提取器更好的选择。
对于算法化词干提取器效果比较差(或者压根没有)的语言,可以使用拼写检查(Hunspell)字典词干提取器

 

1.3.Hunspell 词干提取器

   获取 Hunspell 词典:

一个 Hunspell 词典由两个文件组成 — 具有相同的文件名和两个不同的后缀 — 如 en_US—和下面的两个后缀的其中一个:

.dic:包含所有词根,采用字母顺序,再加上一个代表所有可能前缀和后缀的代码表 【集体称之为词缀( affixes 】

.aff:包含实际 .dic 文件每一行代码表对应的前缀和后缀转换

 

安装一个词典

Hunspell 语汇单元过滤器在特定的 Hunspell 目录里寻找词典, 默认目录是 ./config/hunspell/ 。 .dic 文件和 .aff 文件应该要以子目录且按语言/区域的方式来命名。

config/
  └ hunspell/ 
      └ en_US/ 
          ├ en_US.dic
          ├ en_US.aff
          └ settings.yml
  • Hunspell 目录位置可以通过编辑 config/elasticsearch.yml 文件的:indices.analysis.hunspell.dictionary.location 设置来修改
  • en_US 是这个区域的名字,也是我们传给 hunspell 语汇单元过滤器参数 language 值
  • 一个语言一个设置文件

按语言设置

在语言的目录设置文件 settings.yml 包含适用于所有字典内的语言目录的设置选项。

ignore_case:          true
strict_affix_parsing: true

【说明】

ignore_case

Hunspell 目录默认是区分大小写的,如,姓氏 Booker 和名词 booker 是不同的词,所以应该分别进行词干提取。 也许让 hunspell 提取器区分大小写是一个好主意,不过也可能让事情变得复杂:

  • 一个句子的第一个词可能会被大写,因此感觉上会像是一个名词。

  • 输入的文本可能全是大写,如果这样那几乎一个词都找不到。

  • 用户也许会用小写来搜索名字,在这种情况下,大写开头的词将找不到。

一般来说,设置参数 ignore_case 为 true 是一个好主意。

strict_affix_parsing

词典的质量千差万别。 一些网上的词典的 .aff 文件有很多畸形的规则。 默认情况下,如果 Lucene 不能正常解析一个词缀(affix)规则, 它会抛出一个异常。 你可以通过设置 strict_affix_parsing 为 false 来告诉 Lucene 忽略错误的规则。

自定义词典
如果一个目录放置了多个词典 (.dic 文件), 他们会在加载时合并到一起。这可以让你以自定义的词典的方式对下载的词典进行定制:

config/
  └ hunspell/
      └ en_US/  
          ├ en_US.dic
          ├ en_US.aff 
          ├ custom.dic
          └ settings.yml

custom 词典和 en_US 词典将合并到一起。
多个 .aff 文件是不允许的,因为会产生规则冲突。

.dic 文件和 .aff 文件的格式在这里讨论: 【Hunspell 词典格式】

创建一个 Hunspell 语汇单元过滤器

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "en_US": {
          "type":     "hunspell",
          "language": "en_US" // 参数 language 和目录下对应的名称相同

        }
      },
      "analyzer": {
        "en_US": {
          "tokenizer":  "standard",
          "filter":   [ "lowercase", "en_US" ]
        }
      }
    }
  }
}

[测试]

GET /my_index/_analyze?analyzer=en_US 
reorganizes

返回 organize

GET /_analyze?analyzer=english 
reorganizes

返回 reorgan

[说明]

它不仅能移除前缀还能移除后缀。大多数算法词干提取仅能移除后缀。

Hunspell 词典会占用几兆的内存。幸运的是,Elasticsearch 每个节点只会创建一个词典的单例。 
所有的分片都会使用这个相同的 Hunspell 分析器。

 

Hunspell 词典格式

参考

【分析】在美式英语词典(US English dictionary),en_US.dic 文件包含了一个包含词 analyze 的实体

analyze/ADSG

en_US.aff 文件包含了一个针对标记 A 、 G 、D 和 S 的前后缀的规则。 其中应该只有一个能匹配,每一个规则的格式如下:

[type] [flag] [letters to remove] [letters to add] [condition]

例如,下面的后缀 (SFX) 规则 D 。它是说,当一个词由一个辅音 (除了 a 、e 、i 、o 或 u 外的任意音节) 后接一个 y ,那么它可以移除 y 和添加 ied 结尾 (如,ready → readied )。

SFX    D      y   ied  [^aeiou]y

前面提到的 A 、 G 、D 和 S 标记对应规则如下:

SFX D Y 4
SFX D   0     d          e       -》 analyze 以一个 e 结尾,所以它可以添加一个 d 变成 analyzed
SFX D   y     ied        [^aeiou]y
SFX D   0     ed         [^ey]
SFX D   0     ed         [aeiou]y

SFX S Y 4
SFX S   y     ies        [^aeiou]y
SFX S   0     s          [aeiou]y
SFX S   0     es         [sxzh]
SFX S   0     s          [^sxzhy] -》analyze 不是由 s 、x 、z 、h 或 y 结尾,所以,它可以添加一个 s 变成 analyzes 。

SFX G Y 2
SFX G   e     ing        e 
SFX G   0     ing        [^e]

PFX A Y 1
PFX A   0     re    -》可以添加前缀 re 来形成 reanalyze 。这个规则可以组合后缀规则一起形成: reanalyzes 、reanalyzed 、 reanalyzing 。

 

1.4.选择一个词干提取器

  • english :语汇单元过滤器(token filter)。
  • light_english:语汇单元过滤器(token filter)。
  • minimal_english:Lucene 里面的 EnglishMinimalStemmer ,用来移除复数。
  • lovins:基于Lovins 提取器, 第一个词干提取器。
  • porter:基于 Porter 提取器。
  • porter2:基于 Porter2 提取器。
  • possessive_english:Lucene 里面的 EnglishPossessiveFilter ,移除 's

关于哪个是最好的词干提取器,不存在一个唯一的正确答案 — 它要看你具体的需求。

性能、质量、程度。

 

提取性能

如果一个好的算法词干提取器可用于你的语言,那明智的使用它而不是 Hunspell。它会更快并且消耗更少内存,并且会产生和通常一样好或者比 Hunspell 等价的结果.

如果精度和可定制性对你很重要,那么你需要(和有精力)来维护一个自定义的词典,那么 Hunspell 会给你比算法提取器更大的灵活性。

 

提取程度

不同的词干提取器会将词弱提取或过度提取到一定的程度。 light_ 提取器提干力度不及标准的提取器。 minimal_ 提取器同样也不那么积极。Hunspell 提取力度要激进一些。

是否想要积极提取还是轻量提取取决于你的场景。如果你的搜索结果是要用于聚类算法,你可能会希望匹配的更广泛一点(因此,提取力度要更大一点)。 如果你的搜索结果是面向最终用户,轻量的提取一般会产生更好的结果。对搜索来说,将名称和形容词提干比动词提干更重要,当然这也取决于语言。

另外一个要考虑的因素就是你的文档集的大小。 一个只有 10,000 个产品的小集合,你可能要更激进的提干来确保至少匹配到一些文档。 如果你的文档集很大,使用轻量的弱提取可能会得到更好的匹配结果。

 

选择

从推荐的一个词干提取器出发,如果它工作的很好,那没有什么需要调整的。如果不是,你将需要花点时间来调查和比较该语言可用的各种不同提取器, 来找到最适合你目的的那一个。

 

1.5.控制词干提取

开箱即用的词干提取方案永远也不可能完美。 尤其是算法提取器,他们可以愉快的将规则应用于任何他们遇到的词,包含那些你希望保持独立的词。 也许,在你的场景,保持独立的 skies 和 skiing 是重要的,你不希望把他们提取为 ski (正如 english分析器那样)。

 

阻止词干提取

语言分析器(参数 stem_exclusion 允许我们指定一个词语列表,让他们不被词干提取。

在内部,这些语言分析器使用[语汇单元过滤器] 来标记这些词语列表为 keywords ,用来阻止后续的词干提取过滤器来触碰这些词语。

【举例】

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "no_stem": {
          "type": "keyword_marker",
          "keywords": [ "skies" ] 
        }
      },
      "analyzer": {
        "my_english": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "no_stem",
            "porter_stem"
          ]
        }
      }
    }
  }
}

【测试】

GET /my_index/_analyze?analyzer=my_english
sky skies skiing skis 
返回: sky, skies, ski, ski
 

虽然语言分析器只允许我们通过参数 stem_exclusion 指定一个词语列表来排除词干提取, 不过 keyword_marker 语汇单元过滤器同样
还接收一个 keywords_path 参数允许我们将所有的关键字存在一个文件。 这个文件应该是每行一个字,并且存在于集群的每个节点。

自定义提取

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "custom_stem": {
          "type": "stemmer_override",
          "rules": [ 
            "skies=>sky",
            "mice=>mouse",
            "feet=>foot"
          ]
        }

      },
      "analyzer": {
        "my_english": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "custom_stem", 
            "porter_stem"
          ]
        }
      }
    }
  }
}

GET /my_index/_analyze?analyzer=my_english
The mice came down from the skies and ran over my feet 

返回 themousecamedownfromtheskyandranovermyfoot 

 

原形词干提取

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "unique_stem": {
          "type": "unique",
          "only_on_same_position": true // 为了只有当重复语汇单元出现在相同位置时,移除它们
        }
      },
      "analyzer": {
        "in_situ": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "keyword_repeat",  // 语汇单元过滤器必须出现在词干提取器之前
            "porter_stem",
            "unique_stem" // 过滤器是在词干提取器完成之后移除重复词项
          ]
        }
      }
    }
  }
}

不建议使用原形词干提取

原因如下

  1. 无法区分精准匹配和非精准匹配。
  2. 必须搞清楚 相关度分值是否如何计算的。

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴 韵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值