当前位置:编程学习 > asp >>

HubbleDotNet--自定义分词器

HubbleDotNet 在设计之初就定位为一个开放式的搜索平台,分词器,得分算法,数据库适配器,存储过程,函数等等都可以通过编写自定义的插件来定制。目前版本分词器,数据库适配器的自定义接口已经开放,得分算法的自定义接口也将在最近开放出来。本文将讲述如何编写自己的分词器。

HubbleDotNet 本身自带了3个分词器,分别是盘古分词,简单分词和英文分词。但对于搜索应用来说,仅仅这3种分词器是不够用的,很多应用需要定制化的分词器来提高搜索的准确度。本文通过讲述如何编写一个以逗号分隔的分词器,抛砖引玉。大家可以仿照这个简单的逗号分隔分词器来编写自己的分词器。

逗号分词器主要用于一些分类信息的分解。比如某条记录同时属于  A B C 三个分类,在关系型数据库中,我们可能需要设计2个表,通过主表和分类信息表关联来描述记录的分类关系。在搜索引擎技术中,往往偏向于no-sql ,至少是单表的简单平铺方式,这种方式的查询效率要比关系型要高很多,适合于搜索引擎对大规模数据检索的要求。目前以 google 为代表的搜索引擎基本上都是采用非关系型的设计,所以我们在设计搜索引擎时也最好参照这些搜索巨头的设计理念。回到这个问题,把分类信息平铺到一个表中的方法是增加一个全文索引字段,这个字段中存储这条记录的所属分类,分类之间以逗号分隔(比如 A,B,C)。 这样如果我们要查询属于A或B分类的记录,我们只要写类似如下的语句就可以完成:

select top 10 * from table where title contains ‘xxxx’ and class match ‘A B’ order by score desc

 

分词器的编写
要实现自定义的分词器,我们只需要简单实现 IAnalyzer 和 INamedExternalReference 接口就可以。要实现这个接口,我们要引用

Hubble.Analyzer.dll 和 Hubble.Framework.dll, 这两个动态库在 hubble 安装路径下中可以找到。

并且  using Hubble.Core.Analysis;

 

IAnalyzer 接口
    public interface IAnalyzer
    {
        void Init();
        int Count { get; }
        IEnumerable<WordInfo> Tokenize(string text);
        IEnumerable<WordInfo> TokenizeForSqlClient(string text);
    }
上图为IAnalyzer 接口。下面我分别讲讲这个接口中各个成员的含义

 

Init 函数是用于初始化分词器的,有的分词器比如盘古分词,在调用前需要加载字典,构建内部索引等,这些初始化过程在这个函数中完成。

Count 属性返回 Tokenize 函数分词后的单词总数,这个参数会影响单词的查询权重,由于Tokenize 函数输出是一个 IEnumerable 接口,无法得到单词总数,所以必须通过这个Count属性来得到当前分词的单词总数。

Tokenize 函数输出 text 的分词结果,这个结果以 IEnumerable 接口形式返回,这个函数是用于索引的分词。

TokenizedForSqlClient 函数也是输出text的分词结果,但这个结果是为分解搜索关键字时用的,因为有时候搜索关键字的分词和索引的分词结果不一定完全一致。这个函数只有在搜索时需要通过服务器来帮助分解搜索关键字时才用到,即类似我的例子中的GetKeywordAnalyzerStringFromServer 函数的做法,如果客户端是本地分词,就用不到这个函数。这个函数不影响索引的分词。

 

INamedExternalReference  接口
    public interface INamedExternalReference
    {
        string Name { get; }
    }
上图为 INamedExternalReference  接口,这个接口用于指定分词器的名字

 

下面为逗号分隔分词器代码,我们可以把这个代码编译为一个单独的 dll,在这里我们假设为 SplitByComma.dll

 

using System;
using System.Collections.Generic;
using System.Text;

using Hubble.Core.Analysis;

namespace SplitByComma
{
    public class Split : IAnalyzer, Hubble.Core.Data.INamedExternalReference
    {
        int _Count;
        #region IAnalyzer Members

        /// <summary>
        /// Count of words
        /// </summary>
        public int Count
        {
            get
            {
                return _Count;
            }
        }

        /// <summary>
        /// Initialize the segment
        /// </summary>
        public void Init()
        {
            //Write init code here
        }

        /// <summary>
        /// Tokenize for index
        /// </summary>
        /// <param name="text">text which tokenized to</param>
        /// <returns>word info list</returns>
        public IEnumerable<Hubble.Core.Entity.WordInfo> Tokenize(string text)
        {
            _Count = 0;

            int begin = 0;

            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] == ,)
                {
                    yield return new Hubble.Core.Entity.WordInfo(
                          text.Substring(begin, i - begin), begin);
                    yield return new Hubble.Core.Entity.WordInfo(",", i);
                    begin = i + 1;
                    _Count += 2;
                }
            }

            if (begin < text.Length)
            {
                yield return new Hubble.Core.Entity.WordInfo(
                     text.Substring(begin, text.Length - begin), begin);
                _Count++;
            }
        }

        /// <summary>
        /// Tokenize for search keywords
        /// </summary>
 

补充:Web开发 , ASP.Net ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,