日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

Lucene.Net 2.3.1开发介绍 —— 二、分词(五)

發布時間:2025/3/15 asp.net 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Lucene.Net 2.3.1开发介绍 —— 二、分词(五) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2.1.3?二元分詞

?

上一節通過變換查詢表達式滿足了需求,但是在實際應用中,如果那樣查詢,會出現另外一個問題,因為,那樣搜索,是只要出現這個字,不管它出現在什么位置。這就產生了上一小節開頭講的,對準確性產生了極大干擾。比如,如果有一段這樣的話:“這是一個雄!他有無法用匯形容的孤,但是他并沒有用言來表達。”這句話包含了“英 語 單 詞”這四個字,但是卻和“英語單詞”一點關系都沒有。首先想到的解決方法,就是把句子按詞來劃分,那么就能有效的降低干擾。最簡單的解決方法,莫過于每兩個字組成一個部分。

?

下面來構造核心算法。首先我們期望,只有中文(廣義上指雙字節文字,比如日文,韓文也在這個范圍。)是按照二元拆分,而符號則是單符號拆分,對于英文則保持原樣。因此,需要一個判斷當前字符類型的函數。首先,構造一個枚舉,如代碼2.1.3.1。

?

?

代碼 2.1.3.1

?

Code
///?<summary>
///?Char類型枚舉,用于分詞中類型狀態比較
///?</summary>
public?enum?CharType
{
????None,???
//默認值,不可識別類型
????English,????//拉丁字符,用英文標識
????Chinese,????//CJK字符,以中文代表
????Number,?????//阿拉伯數字
????Control?????//控制符號,指控制符號已經各種標點符號等
}

?

接下來需要有一個函數能夠識別字符,把字符類型轉換成我們需要的CharType。

?

?

代碼 2.1.3.2

?

Code
?1/**////?<summary>
?2///?獲取Char類型
?3///?</summary>
?4///?<param?name="c">字符</param>
?5///?<returns>返回類型</returns>

?6public?static?CharType?GetCharType(char?c)
?7{
?8????switch?(char.GetUnicodeCategory(c))
?9????{
10????????//大小寫字符判斷為英文字符
11????????case?System.Globalization.UnicodeCategory.UppercaseLetter:
12????????case?System.Globalization.UnicodeCategory.LowercaseLetter:
13????????????return?CharType.English;
14????????//其它字符判斷問中文(CJK)
15????????case?System.Globalization.UnicodeCategory.OtherLetter:
16????????????return?CharType.Chinese;
17????????//十進制數字
18????????case?System.Globalization.UnicodeCategory.DecimalDigitNumber:
19????????????return?CharType.Number;
20????????//其他都認為是符號
21????????default:
22????????????return?CharType.Control;
23????}

24}

?

代碼2.1.3.2粗略完成了我們想要的功能。現在就可以構造我們想要的算法了。

?

?

代碼 2.1.3.3

?

Code
??1using?System;
??2using?System.Collections.Generic;
??3using?System.Text;
??4using?Lucene.Net.Analysis;
??5using?System.IO;
??6
??7namespace?Test.Analysis
??8{
??9????public?class?DoubleTokenizer?:?Tokenizer
?10????{
?11????????/**////?<summary>
?12????????///?保持傳入的流
?13????????///?</summary>

?14????????private?TextReader?reader;
?15????????/**////?<summary>
?16????????///?控制分詞器只打開一次
?17????????///?</summary>

?18????????private?bool?done?=?true;
?19????????/**////?<summary>
?20????????///?保存分詞結果
?21????????///?</summary>

?22????????private?List<Token>?tokenlist;
?23
?24????????public?DoubleTokenizer(TextReader?reader)
?25????????{
?26????????????this.reader?=?reader;
?27????????}

?28????????/**////?<summary>
?29????????///?上一個字的類型
?30????????///?</summary>

?31????????private?CharType?lastype?=?CharType.None;
?32????????/**////?<summary>
?33????????///?當前讀取到分詞的記錄數
?34????????///?</summary>

?35????????private?int?ptr?=?0;
?36????????/**////?<summary>
?37????????///?重寫Next方法
?38????????///?</summary>
?39????????///?<param?name="result"></param>
?40????????///?<returns></returns>

?41????????public?override?Token?Next(Token?result)
?42????????{
?43????????????if?(done)???//第一次可以運行,運行后將被設置為false,在一個實例中只會運行一次
?44????????????{
?45????????????????done?=?false;
?46????????????????string?text?=?reader.ReadToEnd();
?47????????????????//輸入為空,則返回結束符號
?48????????????????if?(string.IsNullOrEmpty(text))
?49????????????????????return?null;
?50????????????????//初始化分詞結果
?51????????????????tokenlist?=?new?List<Token>();
?52????????????????//緩沖器,主要用于暫時保存英文數字字符。
?53????????????????StringBuilder?buffer?=?new?StringBuilder();
?54????????????????Token?token;
?55????????????????for?(int?i?=?0;?i?<?text.Length;?i++)
?56????????????????{
?57????????????????????char?nowchar?=?text[i];
?58????????????????????char?nextchar?=?new?char();
?59????????????????????CharType?nowtype?=?GetCharType(nowchar);
?60????????????????????if?(i?<?text.Length?-?1)??//取下一個字符
?61????????????????????????nextchar?=?text[i?+?1];
?62????????????????????//狀態轉換
?63????????????????????if?(nowtype?!=?lastype)
?64????????????????????{
?65????????????????????????lastype?=?nowtype;
?66????????????????????????if?(buffer.Length?>?0)
?67????????????????????????{
?68????????????????????????????token?=?new?Token(buffer.ToString(),?i?-?buffer.Length,?i);
?69????????????????????????????tokenlist.Add(token);
?70????????????????????????????buffer.Remove(0,?buffer.Length);
?71????????????????????????}

?72????????????????????}

?73
?74????????????????????switch?(nowtype)
?75????????????????????{
?76????????????????????????case?CharType.None:
?77????????????????????????case?CharType.Control:
?78????????????????????????????goto?SingleChar;
?79????????????????????????case?CharType.Chinese:
?80????????????????????????????break;
?81????????????????????????case?CharType.English:
?82????????????????????????case?CharType.Number:
?83????????????????????????????buffer.Append(nowchar);
?84????????????????????????????continue;
?85????????????????????}

?86????????????????????//處理連續兩個中文字符
?87????????????????????if?(GetCharType(nextchar)?==?CharType.Chinese)
?88????????????????????{
?89????????????????????????token?=?new?Token(nowchar.ToString()?+?nextchar.ToString(),?i,?i?+?2);
?90????????????????????????tokenlist.Add(token);
?91????????????????????????i++;
?92????????????????????????continue;
?93????????????????????}

?94
?95????????????????SingleChar:?????//處理單個字符
?96????????????????????token?=?new?Token(nowchar.ToString(),?i,?i?+?1);
?97????????????????????tokenlist.Add(token);
?98????????????????????continue;
?99????????????????}

100????????????????//返回第一個分詞結果,并且把指針移向下一位
101????????????????return?tokenlist[ptr++];
102????????????}

103????????????else
104????????????{
105????????????????//在分詞結果范圍內取詞
106????????????????if?(ptr?<?tokenlist.Count)
107????????????????????return?tokenlist[ptr++];
108????????????????//超出則返回結束符號
109????????????????return?null;
110????????????}

111????????}

112????????/**////?<summary>
113????????///?獲取Char類型
114????????///?</summary>
115????????///?<param?name="c">字符</param>
116????????///?<returns>返回類型</returns>

117????????public?static?CharType?GetCharType(char?c)
118????????{
119????????????switch?(char.GetUnicodeCategory(c))
120????????????{
121????????????????//大小寫字符判斷為英文字符
122????????????????case?System.Globalization.UnicodeCategory.UppercaseLetter:
123????????????????case?System.Globalization.UnicodeCategory.LowercaseLetter:
124????????????????????return?CharType.English;
125????????????????//其它字符判斷問中文(CJK)
126????????????????case?System.Globalization.UnicodeCategory.OtherLetter:
127????????????????????return?CharType.Chinese;
128????????????????//十進制數字
129????????????????case?System.Globalization.UnicodeCategory.DecimalDigitNumber:
130????????????????????return?CharType.Number;
131????????????????//其他都認為是符號
132????????????????default:
133????????????????????return?CharType.Control;
134????????????}

135????????}

136????}

137????/**////?<summary>
138????///?Char類型枚舉,用于分詞中類型狀態比較
139????///?</summary>

140????public?enum?CharType
141????{
142????????None,???//默認值,不可識別類型
143????????English,????//拉丁字符,用英文標識
144????????Chinese,????//CJK字符,以中文代表
145????????Number,?????//阿拉伯數字
146????????Control?????//控制符號,指控制符號已經各種標點符號等
147????}

148
149}

?

代碼2.1.3.3就是構造完后的算法。意思就是把英文字母,數字按空格或者符號劃分,而中文則二元拆分。現在來測試下效果。

?

?

代碼 2.1.3.4

?

Code
?1using?System;
?2using?System.Collections.Generic;
?3using?System.Text;
?4using?NUnit.Framework;
?5using?System.IO;
?6using?Lucene.Net.Analysis;
?7
?8namespace?Test.Analysis
?9{
10????[TestFixture]
11????public?class?DoubleTokenizerTest
12????{
13????????[Test]
14????????public?void?NextTest()
15????????{
16????????????string?testwords?=?"我是一個中國人,代碼yurow001,真是個好名字啊!!!哈哈哈。。。";
17????????????DoubleTokenizer?tk?=?new?DoubleTokenizer(new?StringReader(testwords));
18????????????Token?token;
19????????????while?((token?=?tk.Next())?!=?null)
20????????????{
21????????????????Console.WriteLine(token.TermText()?+?"\t"?+?token.StartOffset()?+?"\t"?+?token.EndOffset());
22????????????}

23????????????tk.Close();
24????????}

25????}

26}

27

?

代碼 2.1.3.4 就是測試代碼,測試的輸入包含了各種字符。來看一下效果。

?

測試結果:

?

我是?0?2
一個?2?4
中國?4?6
人?6?7
,?7?8
代碼?8?10
yurow?10?15
001?15?18
,?18?19
真是?19?21
個好?21?23
名字?23?25
啊?25?26
!?26?27
!?27?28
!?28?29
哈哈?29?31
哈?31?32
。?32?33
。?33?34
。?34?35

?

應該說結果符合我們的預期。下來寫個Analyzer包裝,并把這個包裝應用到上一節2.1.2?的方案里去。

?

?

代碼 2.1.3.5

?

Code
?1using?System;
?2using?System.Collections.Generic;
?3using?System.Text;
?4using?Lucene.Net.Analysis;
?5
?6namespace?Test.Analysis
?7{
?8????public?class?DoubleAnalyzer?:?Analyzer
?9????{
10????????public?override?TokenStream?TokenStream(string?fieldName,?System.IO.TextReader?reader)
11????????{
12????????????return?new?DoubleTokenizer(reader);
13????????}

14????}

15}

16

?

代碼2.1.3.5就是包裝的結果。測試結果:

搜索詞:英語
結果:
content:英語
-----------------------------------
搜索詞:語法
結果:
content:語法
-----------------------------------
搜索詞:單詞
結果:
content:單詞
-----------------------------------
搜索詞:口語
結果:
content:口語
-----------------------------------
搜索詞:+content:"英" +content:"語" +content:"單" +content:"詞"
結果:
+content:英 +content:語 +content:單 +content:詞
-----------------------------------

What's happened? 為什么沒有結果?分詞器寫錯了?不要灰心!讓我們來分析一下。在DoubleTokenizer類構造函數下一個斷點,調試。因為,如果能正確運行,這個構造函數肯定要進入的。調試后看到了什么?傳入的TextReader的類型是Lucene.Net.Index.DocumentsWriter.ReusableStringReader。查看Lucene.Net.Index.DocumentsWriter.ReusableStringReader類的定義,它繼承自StringReader類,但是它重寫掉了一些方法,而且,我們并沒有發現我們使用的ReadToEnd方法。問題可能出在這里。看到ReusableStringReader類重寫的Read(char[],int,int)方法,試試這個。

?

?

代碼 2.1.3.6

?

Code
??1using?System;
??2using?System.Collections.Generic;
??3using?System.Text;
??4using?Lucene.Net.Analysis;
??5using?System.IO;
??6
??7namespace?Test.Analysis
??8{
??9????public?class?DoubleTokenizer?:?Tokenizer
?10????{
?11????????/**////?<summary>
?12????????///?保持傳入的流
?13????????///?</summary>
?14????????//private?TextReader?reader;
?15????????/**////?<summary>
?16????????///?控制分詞器只打開一次
?17????????///?</summary>

?18????????private?bool?done?=?true;
?19????????/**////?<summary>
?20????????///?保存分詞結果
?21????????///?</summary>

?22????????private?List<Token>?tokenlist;
?23
?24????????public?DoubleTokenizer(TextReader?reader)
?25????????{
?26????????????this.input?=?reader;
?27????????}

?28????????/**////?<summary>
?29????????///?上一個字的類型
?30????????///?</summary>

?31????????private?CharType?lastype?=?CharType.None;
?32????????/**////?<summary>
?33????????///?當前讀取到分詞的記錄數
?34????????///?</summary>

?35????????private?int?ptr?=?0;
?36????????/**////?<summary>
?37????????///?重寫Next方法
?38????????///?</summary>
?39????????///?<param?name="result"></param>
?40????????///?<returns></returns>

?41????????public?override?Token?Next(Token?result)
?42????????{
?43????????????if?(done)???//第一次可以運行,運行后將被設置為false,在一個實例中只會運行一次
?44????????????{
?45????????????????done?=?false;
?46
?47????????????????//-------------------------------------------------------
?48????????????????//使用傳入參數作為緩沖區
?49????????????????char[]?charbuffer?=?result.TermBuffer();
?50????????????????int?upto?=?0;
?51????????????????result.Clear();
?52????????????????while?(true)
?53????????????????{
?54????????????????????int?length?=?input.Read(charbuffer,?upto,?charbuffer.Length?-?upto);
?55????????????????????if?(length?<=?0)
?56????????????????????????break;
?57????????????????????upto?+=?length;
?58????????????????????if?(upto?==?charbuffer.Length)
?59????????????????????????charbuffer?=?result.ResizeTermBuffer(1?+?charbuffer.Length);
?60????????????????}

?61????????????????result.SetTermLength(upto);
?62????????????????//------------------------------------------------------
?63????????????????string?text?=?result.TermText();
?64????????????????//輸入為空,則返回結束符號
?65????????????????if?(string.IsNullOrEmpty(text))
?66????????????????????return?null;
?67????????????????//初始化分詞結果
?68????????????????tokenlist?=?new?List<Token>();
?69????????????????//緩沖器,主要用于暫時保存英文數字字符。
?70????????????????StringBuilder?buffer?=?new?StringBuilder();
?71????????????????Token?token;
?72????????????????for?(int?i?=?0;?i?<?text.Length;?i++)
?73????????????????{
?74????????????????????char?nowchar?=?text[i];
?75????????????????????char?nextchar?=?new?char();
?76????????????????????CharType?nowtype?=?GetCharType(nowchar);
?77????????????????????if?(i?<?text.Length?-?1)??//取下一個字符
?78????????????????????????nextchar?=?text[i?+?1];
?79????????????????????//狀態轉換
?80????????????????????if?(nowtype?!=?lastype)
?81????????????????????{
?82????????????????????????lastype?=?nowtype;
?83????????????????????????if?(buffer.Length?>?0)
?84????????????????????????{
?85????????????????????????????token?=?new?Token(buffer.ToString(),?i?-?buffer.Length,?i);
?86????????????????????????????tokenlist.Add(token);
?87????????????????????????????buffer.Remove(0,?buffer.Length);
?88????????????????????????}

?89????????????????????}

?90
?91????????????????????switch?(nowtype)
?92????????????????????{
?93????????????????????????case?CharType.None:
?94????????????????????????case?CharType.Control:
?95????????????????????????????goto?SingleChar;
?96????????????????????????case?CharType.Chinese:
?97????????????????????????????break;
?98????????????????????????case?CharType.English:
?99????????????????????????case?CharType.Number:
100????????????????????????????buffer.Append(nowchar);
101????????????????????????????continue;
102????????????????????}

103????????????????????//處理連續兩個中文字符
104????????????????????if?(GetCharType(nextchar)?==?CharType.Chinese)
105????????????????????{
106????????????????????????token?=?new?Token(nowchar.ToString()?+?nextchar.ToString(),?i,?i?+?2);
107????????????????????????tokenlist.Add(token);
108????????????????????????i++;
109????????????????????????continue;
110????????????????????}

111
112????????????????SingleChar:?????//處理單個字符
113????????????????????token?=?new?Token(nowchar.ToString(),?i,?i?+?1);
114????????????????????tokenlist.Add(token);
115????????????????????continue;
116????????????????}

117????????????????//返回第一個分詞結果,并且把指針移向下一位
118????????????????return?tokenlist[ptr++];
119????????????}

120????????????else
121????????????{
122????????????????//在分詞結果范圍內取詞
123
124????????????????if?(ptr?<?tokenlist.Count)
125????????????????{
126????????????????????return?tokenlist[ptr++];
127????????????????}

128????????????????//超出則返回結束符號
129????????????????return?null;
130????????????}

131????????}

132????????/**////?<summary>
133????????///?獲取Char類型
134????????///?</summary>
135????????///?<param?name="c">字符</param>
136????????///?<returns>返回類型</returns>

137????????public?static?CharType?GetCharType(char?c)
138????????{
139????????????switch?(char.GetUnicodeCategory(c))
140????????????{
141????????????????//大小寫字符判斷為英文字符
142????????????????case?System.Globalization.UnicodeCategory.UppercaseLetter:
143????????????????case?System.Globalization.UnicodeCategory.LowercaseLetter:
144????????????????????return?CharType.English;
145????????????????//其它字符判斷問中文(CJK)
146????????????????case?System.Globalization.UnicodeCategory.OtherLetter:
147????????????????????return?CharType.Chinese;
148????????????????//十進制數字
149????????????????case?System.Globalization.UnicodeCategory.DecimalDigitNumber:
150????????????????????return?CharType.Number;
151????????????????//其他都認為是符號
152????????????????default:
153????????????????????return?CharType.Control;
154????????????}

155????????}

156????}

157????/**////?<summary>
158????///?Char類型枚舉,用于分詞中類型狀態比較
159????///?</summary>

160????public?enum?CharType
161????{
162????????None,???//默認值,不可識別類型
163????????English,????//拉丁字符,用英文標識
164????????Chinese,????//CJK字符,以中文代表
165????????Number,?????//阿拉伯數字
166????????Control?????//控制符號,指控制符號已經各種標點符號等
167????}

168
169}

170

?

代碼改造成了2.1.3.6。主要的改變在于用父類的input字段保持了讀入流,然后用Token作為緩沖區,因為它實現了可變緩沖區,簡化了我們的開發。測試結果。

?

搜索詞:英語
結果:
content:英語
英語單詞,語法,口語都很重要。
口語,語法,單詞都是英語的重要組成部分。
-----------------------------------
搜索詞:語法
結果:
content:語法
英語單詞,語法,口語都很重要。
口語,語法,單詞都是英語的重要組成部分。
-----------------------------------
搜索詞:單詞
結果:
content:單詞
英語單詞,語法,口語都很重要。
口語,語法,單詞都是英語的重要組成部分。
我們要學好英語不但要學語法,單詞還有口語。
-----------------------------------
搜索詞:口語
結果:
content:口語
英語單詞,語法,口語都很重要。
口語,語法,單詞都是英語的重要組成部分。
我們要學好英語不但要學語法,單詞還有口語。
-----------------------------------
搜索詞:+content:"英" +content:"語" +content:"單" +content:"詞"
結果:
+content:英 +content:語 +content:單 +content:詞
-----------------------------------

終于OK了!!!呵呵。

?

(PS:長時間編寫,可能內容太長了,造成我機器編寫這個章節有點卡,所以,這里提前結束。)


?

?

轉載于:https://www.cnblogs.com/birdshover/archive/2008/08/31/1279894.html

總結

以上是生活随笔為你收集整理的Lucene.Net 2.3.1开发介绍 —— 二、分词(五)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。