`

有关Lucene的问题(2):stemming和lemmatization

阅读更多

问题:

我试验了一下文章中提到的 stemming 和 lemmatization

  • 将单词缩减为词根形式,如“cars”到“car”等。这种操作称为:stemming。
  • 将单词转变为词根形式,如“drove”到“drive”等。这种操作称为:lemmatization。

试验没有成功

代码如下:

public class TestNorms {   
    public void createIndex() throws IOException {   
        Directory d = new SimpleFSDirectory(new File("d:/falconTest/lucene3/norms"));   
        IndexWriter writer = new IndexWriter(d, new StandardAnalyzer(Version.LUCENE_30), 
                                                                                      true, IndexWriter.MaxFieldLength.UNLIMITED);   
        Field field = new Field("desc", "", Field.Store.YES, Field.Index.ANALYZED);   
        Document doc = new Document();   
        field.setValue("Hello students was drive");   
        doc.add(field);   
        writer.addDocument(doc);   
        writer.optimize();   
        writer.close();   
    }   
    public void search() throws IOException {   
        Directory d = new SimpleFSDirectory(new File("d:/falconTest/lucene3/norms"));   
        IndexReader reader = IndexReader.open(d);   
        IndexSearcher searcher = new IndexSearcher(reader);   
        TopDocs docs = searcher.search(new TermQuery(new Term("desc","drove")), 10);   
        System.out.println(docs.totalHits);   
    }   
    public static void main(String[] args) throws IOException {   
        TestNorms test= new TestNorms();   
        test.createIndex();   
        test.search();   
    }   

不管是单复数,还是单词的变化,都是没有体现的

不知道是不是分词器的原因?

回答:

的确是分词器的问题,StandardAnalyzer并不能进行stemming和lemmatization,因而不能够区分单复数和词型。

文章中讲述的是全文检索的基本原理,理解了他,有利于更好的理解Lucene,但不代表Lucene是完全按照此基本流程进行的。

(1) 有关stemming

作为stemming,一个著名的算法是The Porter Stemming Algorithm,其主页为http://tartarus.org/~martin/PorterStemmer/,也可查看其论文http://tartarus.org/~martin/PorterStemmer/def.txt

通过以下网页可以进行简单的测试:Porter's Stemming Algorithm Online[http://facweb.cs.depaul.edu/mobasher/classes/csc575/porter.html]

cars –> car

driving –> drive

tokenization –> token

然而

drove –> drove

可见stemming是通过规则缩减为词根的,而不能识别词型的变化。

在最新的Lucene 3.0中,已经有了PorterStemFilter这个类来实现上述算法,只可惜没有Analyzer向匹配,不过不要紧,我们可以简单实现:

public class PorterStemAnalyzer extends Analyzer
{
    @Override
    public TokenStream tokenStream(String fieldName, Reader reader) {
      return new PorterStemFilter(new LowerCaseTokenizer(reader));
    }
}

把此分词器用在你的程序中,就能够识别单复数和规则的词型变化了。

public void createIndex() throws IOException {
  Directory d = new SimpleFSDirectory(new File("d:/falconTest/lucene3/norms"));
  IndexWriter writer = new IndexWriter(d, new PorterStemAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);

  Field field = new Field("desc", "", Field.Store.YES, Field.Index.ANALYZED);
  Document doc = new Document();
  field.setValue("Hello students was driving cars professionally");
  doc.add(field);

  writer.addDocument(doc);
  writer.optimize();
  writer.close();
}

public void search() throws IOException {
  Directory d = new SimpleFSDirectory(new File("d:/falconTest/lucene3/norms"));
  IndexReader reader = IndexReader.open(d);
  IndexSearcher searcher = new IndexSearcher(reader);
  TopDocs docs = searcher.search(new TermQuery(new Term("desc", "car")), 10);
  System.out.println(docs.totalHits);
  docs = searcher.search(new TermQuery(new Term("desc", "drive")), 10);
  System.out.println(docs.totalHits);
  docs = searcher.search(new TermQuery(new Term("desc", "profession")), 10);
  System.out.println(docs.totalHits);
}

(2) 有关lemmatization

至于lemmatization,一般是有字典的,方能够由"drove"对应到"drive".

在网上搜了一下,找到European languages lemmatizer[http://lemmatizer.org/],只不过是在linux下面C++开发的,有兴趣可以试验一下。

首先按照网站的说明下载,编译,安装:

libMAFSA is the core of the lemmatizer. All other libraries depend on it. Download the last version from the following page, unpack it and compile:

# tar xzf libMAFSA-0.2.tar.gz
# cd libMAFSA-0.2/
# cmake .
# make
# sudo make install
After this you should install libturglem. You can download it at the same place.
# tar xzf libturglem-0.2.tar.gz
# cd libturglem-0.2
# cmake .
# make
# sudo make install
Next you should install english dictionaries with some additional features to work with.
# tar xzf turglem-english-0.2.tar.gz
# cd turglem-english-0.2
# cmake .
# make
# sudo make install

安装完毕后:

  • /usr/local/include/turglem是头文件,用于编译自己编写的代码
  • /usr/local/share/turglem/english是字典文件,其中lemmas.xml中我们可以看到"drove"和"drive"的对应,"was"和"be"的对应。
  • /usr/local/lib中的libMAFSA.a  libturglem.a  libturglem-english.a  libtxml.a是用于生成应用程序的静态库

<l id="DRIVE" p="6" />

<l id="DROVE" p="6" />

<l id="DRIVING" p="6" />

在turglem-english-0.2目录下有例子测试程序test_utf8.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <turglem/lemmatizer.h>
#include <turglem/lemmatizer.hpp>
#include <turglem/english/charset_adapters.hpp>

int main(int argc, char **argv)
{
        char in_s_buf[1024];
        char *nl_ptr;

        tl::lemmatizer lem;

        if(argc != 4)
        {
                printf("Usage: %s words.dic predict.dic flexias.bin\n", argv[0]);
                return -1;
        }

        lem.load_lemmatizer(argv[1], argv[3], argv[2]);

        while (!feof(stdin))
        {
                fgets(in_s_buf, 1024, stdin);
                nl_ptr = strchr(in_s_buf, '\n');
                if (nl_ptr) *nl_ptr = 0;
                nl_ptr = strchr(in_s_buf, '\r');
                if (nl_ptr) *nl_ptr = 0;

                if (in_s_buf[0])
                {
                        printf("processing %s\n", in_s_buf);
                        tl::lem_result pars;
                        size_t pcnt = lem.lemmatize<english_utf8_adapter>(in_s_buf, pars);
                        printf("%d\n", pcnt);
                        for (size_t i = 0; i < pcnt; i++)
                        {
                                std::string s;
                                u_int32_t src_form = lem.get_src_form(pars, i);
                                s = lem.get_text<english_utf8_adapter>(pars, i, 0);
                                printf("PARADIGM %d: normal form '%s'\n", (unsigned int)i, s.c_str());
                                printf("\tpart of speech:%d\n", lem.get_part_of_speech(pars, (unsigned int)i, src_form));
                        }
                }
        }

        return 0;
}

编译此文件,并且链接静态库:注意链接顺序,否则可能出错。

g++ -g -o output test_utf8.cpp -L/usr/local/lib/ -lturglem-english -lturglem -lMAFSA –ltxml

运行编译好的程序:

./output /usr/local/share/turglem/english/dict_english.auto

/usr/local/share/turglem/english/prediction_english.auto

/usr/local/share/turglem/english/paradigms_english.bin

做测试,虽然对其机制尚不甚了解,但是可以看到lemmatization的作用:

drove
processing drove
3
PARADIGM 0: normal form 'DROVE'
        part of speech:0
PARADIGM 1: normal form 'DROVE'
        part of speech:2
PARADIGM 2: normal form 'DRIVE'
        part of speech:2

was
processing was
3
PARADIGM 0: normal form 'BE'
        part of speech:3
PARADIGM 1: normal form 'BE'
        part of speech:3
PARADIGM 2: normal form 'BE'
        part of speech:3

分享到:
评论
1 楼 illu 2010-02-06  
谢谢您的回答 我这里还有一个问题不解
其实上面那个类本来是我测试norms时用的 没有测试成功 然后我才又测试了一下 stemming 与 lemmatization
问题是这样的

在创建Field时 都会用到Index
Index.NO
Index.ANALYZED
Index.NOT_ANALYZED
这三个我明白
但是其余两个
Index.NOT_ANALYZED_NO_NORMS
Index.ANALYZED_NO_NORMS
我还是搞不清楚。。

特别是norms这个概念 不知道是干什么
从字面上理解 norm 就是规范化
可能是去标点 去除一些无意义的词
但是根据我的测试
比如说用Index.ANALYZED 和Index.ANALYZED_NO_NORMS 结果是一模一样的
然后我又翻了下源码
如下:
/** Expert: Index the field's value without an Analyzer,
     * and also disable the storing of norms.  Note that you
     * can also separately enable/disable norms by calling
     * {@link Field#setOmitNorms}.  No norms means that
     * index-time field and document boosting and field
     * length normalization are disabled.  The benefit is
     * less memory usage as norms take up one byte of RAM
     * per indexed field for every document in the index,
     * during searching.  Note that once you index a given
     * field <i>with</i> norms enabled, disabling norms will
     * have no effect.  In other words, for this to have the
     * above described effect on a field, all instances of
     * that field must be indexed with NOT_ANALYZED_NO_NORMS
     * from the beginning. */
    NOT_ANALYZED_NO_NORMS {
      @Override
      public boolean isIndexed()  { return true;  }
      @Override
      public boolean isAnalyzed() { return false; }
      @Override
      public boolean omitNorms()  { return true;  }   	
    },

    /** Expert: Index the tokens produced by running the
     *  field's value through an Analyzer, and also
     *  separately disable the storing of norms.  See
     *  {@link #NOT_ANALYZED_NO_NORMS} for what norms are
     *  and why you may want to disable them. */
    ANALYZED_NO_NORMS {
      @Override
      public boolean isIndexed()  { return true;  }
      @Override
      public boolean isAnalyzed() { return true;  }
      @Override
      public boolean omitNorms()  { return true;  }   	
    };


还是搞不懂

所以还想问问您
Index.NOT_ANALYZED_NO_NORMS
Index.ANALYZED_NO_NORMS
norm的概念  NO_NORMS到底是做了什么
谢谢

相关推荐

    lucene的小案例

    这个过程包括分词(Tokenization)、词干提取(Stemming)和词性还原(Lemmatization)等,目的是提高搜索速度和准确性。 2. **文档(Document)**:在Lucene中,每个文档代表要索引的信息单元,可以是一个网页、...

    lucene原理与代码分析完整版

    - Stemming和Lemmatization的区别及其在全文检索中的应用。 - 向量空间模型与Lucene的打分机制之间的联系。 - 影响Lucene文档评分的多种因素。 - Lucene中的TooManyClauses异常及其解决方法。 通过上述内容的学习,...

    Lucene+3.0+原理与代码分析完整版

    2. **词干提取(Stemming)与词形还原(Lemmatization)的区别**:词干提取旨在减少词汇的变体形式到其基本形式,而词形还原则是将词汇还原为其字典形式,通常更准确但也更复杂。 3. **向量空间模型与 Lucene 的...

    LUCENE搜索引擎基本工作原理

    同时,它还会执行其他预处理操作,如去除停用词(Stopwords)、词干提取(Stemming)和词形还原(Lemmatization)。 3. **建立倒排索引**:每个词被分配一个唯一的ID,然后记录这个词在哪些文档中出现,以及在这些...

    关于lucene建立数据库索引的更新说明

    在本文中,我们将探讨如何使用Lucene建立数据库索引,并分享一些在实践过程中的经验和教训。Lucene是一个高性能、全文本搜索库,广泛用于构建搜索引擎。在创建索引时,需要注意以下关键点: 1. **资料的准确性**:...

    lucene2.3.1

    1. 文档分析与预处理:Lucene首先对输入的文本进行分词(Tokenization),然后去除停用词(Stopword Removal)和标点符号,进行词干提取(Stemming)和词形还原(Lemmatization),以便减少词汇变化对搜索的影响。...

    Lucene In Action中文版第三章

    令牌修改阶段包括了各种过滤操作,如词形还原(Lemmatization)、停用词去除(Stop Word Removal)、词干提取(Stemming)等。这些操作旨在减少索引的大小,提高搜索效率,并增强查询的相关性。词形还原将词还原到其基本...

    Lucene-common-functions-introduced_v1

    它包括分词(Tokenization)、去除停用词(Stop Word Removal)、词干提取(Stemming)和词形还原(Lemmatization)等。分词是将句子拆分成单个词汇;去除停用词是为了减少无意义的词对搜索结果的影响;词干提取和词...

    开发自己的搜索引擎——Lucene+Heritrix(第2版)光盘内容

    通过Lucene,开发者可以轻松地在大量数据中快速定位到相关信息。 Heritrix是另一个开源项目,它是一个网络抓取器,用于爬取互联网上的网页,收集数据以供后续处理,如搜索引擎的索引构建。Heritrix提供了一种可配置...

    Lucene 3.0 原理与代码分析完整版

    另外,stemming(词干提取)和lemmatization(词形还原)是两种不同的文本预处理方式,它们影响查询的精度和召回率。在构建实时索引时,为了保持系统的响应速度,需要对索引策略进行优化,以达到快速更新索引的目的...

    Lucene 例子

    这通常包括分词(Tokenization)、去除停用词(Stopword Removal)、词干提取(Stemming)和词形还原(Lemmatization)。例如,在 LuceneDemo1 中,我们可能会看到一个定制的 Analyzer 类,用于处理特定语言或领域的...

    Lucene 原理与代码分析完整版.pdf

    这一步可能包括去除停用词(如“the”, “and”等)、词干提取(stemming)、词形还原(lemmatization)等操作,以减少词项数量并提高检索效率。 **第四步:索引组件(Indexer)** 经过处理后的词项被传送给索引...

    lecene原理与代码分析

    此外,Lucene的分词策略(stemming和lemmatization)和文档打分机制也会影响最终的搜索结果。为了解决这些问题,需要深入理解Lucene的内部工作机制,并对索引过程和查询策略进行适当调整。 综上所述,全文检索技术...

    java搜索引擎代码(热门)

    3. **文本预处理**:包括去除停用词(如“的”、“和”等常见词汇)、词干提取(Stemming)和词形还原(Lemmatization),目的是减少词汇变体,提高搜索准确性。 4. **查询解析(Query Parsing)**:将用户的输入...

    Java检索引擎

    5. **文本分析和预处理**:包括去除停用词(Stop Words)、词干提取(Stemming)和词形还原(Lemmatization)等文本处理技术。 6. **性能优化**:如何通过调整索引策略、查询优化和硬件配置来提升检索速度和效率。 ...

    stem_java.rar_stem ja

    标签"stem_ja"可能是指这个程序是针对英文("ja"可能是指“Java”或“Japanese”,但描述中明确指出是英文处理)的,并且与词干提取(Stemming)有关。Java作为一种多平台的、面向对象的编程语言,提供了丰富的库和...

    搜索引擎中的分词以及查找的编程心得

    在探讨搜索引擎中的分词技术和查找机制之前,我们首先需要理解几个基本概念:分词(Tokenization)、词干提取(Stemming)和词形还原(Lemmatization)。这些技术是构建高效、准确搜索引擎的核心。 #### 一、分词...

Global site tag (gtag.js) - Google Analytics