導航:首頁 > 源碼編譯 > java正向最大匹配演算法

java正向最大匹配演算法

發布時間:2022-05-17 18:56:03

① 請問什麼是百度演算法

隨著搜索經濟的崛起,人們開始越加關注全球各大搜索引擎的性能、技術和日流量。作為企業,會根據搜索引擎的知名度以及日流量來選擇是否要投放廣告等;作為普通網民,會根據搜索引擎的性能和技術來選擇自己喜歡的引擎查找資料;作為技術人員,會把有代表性的搜索引擎作為研究對象. 搜索引擎經濟的崛起,又一次向人們證明了網路所蘊藏的巨大商機。網路離開了搜索將只剩下空洞雜亂的數據,以及大量等待去費力挖掘的金礦。
但是,如何設計一個高效的搜索引擎?我們可以以bd所採取的技術手段來探討如何設計一個實用的搜索引擎.搜索引擎涉及到許多技術點,比如查詢處理,排序演算法,頁面抓取演算法,CACHE機制,ANTI-SPAM等等.這些技術細節,作為商業公司的搜索引擎服務提供商比如bd,GOOGLE等是不會公之於眾的.我們可以將現有的搜索引擎看作一個黑盒,通過向黑盒提交輸入,判斷黑盒返回的輸出大致判斷黑盒裡面不為人知的技術細節.
查詢處理與分詞是一個中文搜索引擎必不可少的工作,而bd作為一個典型的中文搜索引擎一直強調其」中文處理」方面具有其它搜索引擎所不具有的關鍵技術和優勢.那麼我們就來看看bd到底採用了哪些所謂的核心技術.
我們分兩個部分來講述:查詢處理/中文分詞.
一. 查詢處理
用戶向搜索引擎提交查詢,搜索引擎一般在接受到用戶查詢後要做一些處理,然後在索引資料庫裡面提取相關的信息.那麼bd在接受到用戶查詢後做了些什麼工作呢?
1. 假設用戶提交了不只一個查詢串,比如」信息檢索 理論 工具」.那麼搜索引擎首先做的是根據分隔符比如空格,標點符號,將查詢串分割成若乾子查詢串,比如上面的查詢就會被解析為:<信息檢索,理論,工具>三個子字元串;這個道理簡單,我們接著往下看.
2. 假設提交的查詢有重復的內容,搜索引擎怎麼處理呢?比如查詢」理論 工具 理論」,bd是將重復的字元串當作只出現過一次,也就是處理成等價的」理論 工具」,而GOOGLE顯然是沒有進行歸並,而是將重復查詢子串的權重增大進行處理.那麼是如何得出這個結論的呢?我們可以將」理論 工具」提交給bd,返回341,000篇文檔,大致看看第一頁的返回內容.OK.繼續,我們提交查詢」理論 工具 理論」,在看看返回結果,仍然是那麼多返迴文檔,當然這個不能說明太多問題,那看看第一頁返回結果的排序,看出來了嗎?順序完全沒有變化,而GOOGLE則排序有些變動,這說明bd是將重復的查詢歸並成一個處理的,而且字元串之間的先後出現順序基本不予考慮(GOOGLE是考慮了這個順序關系的).
3. 假設提交的中文查詢包含英文單詞,搜索引擎是怎麼處理的?比如查詢」電影BT下載」,bd的方法是將中文字元串中的英文當作一個整體保留,並以此為斷點將中文切分開,這樣上述的查詢就切為<電影,BT,下載>,不論中間的英文是否一個字典里能查到的單詞也好,還是隨機的字元也好,都會當作一個整體來對待.至於為什麼,你用查詢」 電影dfdfdf下載」看看結果就知道了.當然如果查詢中包含數字,也是如此辦理.
到目前為止,一切很簡單,也很清楚,bd怎麼處理用戶查詢的呢?歸納如下:首先根據分割符號將查詢分開,然後看看是否有重復的字元串,如果有,就拋棄多餘的,只保留一個,接著判斷是否有英文或者數字,如果有的話,把英文或者數字當作一個整體保留並把前後的中文切開
接著該干什麼呢?該考慮分詞的問題了.
二. 中文分詞
首先,講講bd的分詞時機或者條件問題,是否是個中文字元串bd就拿來切一下呢?非也,要想被bd的分詞程序榮幸的切割一下也是要講條件的,哪能是個字元串就切割啊?你當bd是賣鋸條的么?
那麼什麼樣的字元串才滿足被切割的條件呢?簡單說來,如果字元串只包含小於等於3個中文字元的話,那就保留不動,當字元串長度大於4個中文字元的時候,bd的分詞程序才出馬大幹快上,把這個字元串肢解掉.
怎麼證明呢?我們向bd提交」電影下載」,看看返回結果中標為紅字的地方,不難看出來,查詢已經被切割成<電影,下載>兩個單詞了,說明分詞程序已經開工了,如果是比4個中文字元更長的字元串,那分詞程序就更不客氣了,一定大卸八塊而後快.我們來看看三個字元的情況,提交查詢」當然擇」,看起來這個查詢不倫不類,那是因為我希望看到這個字元串被切分為<當然,擇>,返回結果365篇相關頁面,翻到最後一頁,發現標紅的關鍵字都是」當然擇」連續出現的情況,好像沒有切分,但是還不確定,那麼再提交人工分好的查詢」當然 擇」看看,返回結果1,090,000篇,基本上可以確定沒有進行分詞了,當然另外一種解釋是:對於三個字元先切分,然後將切分後的結果當作一個短語查詢,這樣看到的效果和沒有切分是相似的.但是我傾向於判斷bd對於少於3個字元的串沒有切分,奧卡姆不是說了么」如無必要,勿增實體」,干嗎做無用功呢.那麼如果沒有切分,會有一個隨之而來的問題,怎麼從索引庫裡面提取未切分的字元串呢?這牽扯到索引的問題,我覺得bd應該採取了兩套索引機制,一種是按照單詞索引,一種是按照N-GRAM索引,至於索引的具體問題,以後在詳細論述.
下面我們看看bd是採取的何種分詞演算法,現在分詞演算法已經算是比較成熟了,有簡單的有復雜的,比如正向最大匹配,反向最大匹配,雙向最大匹配,語言模型方法,最短路徑演算法等等,有興趣的可以用GOOGLE去搜索一下以增加理解.這里就不展開說了.但是要記住一點的是:判斷一個分詞系統好不好,關鍵看兩點,一個是消除歧義能力;一個是詞典未登錄詞的識別比如人名,地名,機構名等.
那麼bd用的是什麼方法?我的判斷是用雙向最大匹配演算法.至於怎麼推理得出的,讓我們一步步來看.當然,這里首先有個假設,bd不會採取比較復雜的演算法,因為考慮到速度問題.

我們提交一個查詢」毛澤東北京華煙雲」,又一個不知所雲的查詢,盡管不知所雲但是自有它的道理,我想看看bd的分詞是如何消歧以及是否有詞典未登錄詞的識別的功能,如果是正向最大匹配演算法的話,那麼輸出應該是:」毛澤東/北京/華/煙雲」,如果是反向最大匹配演算法的話,那麼輸出應該是:」毛/澤/東北/京華煙雲」,我們看看bd的分詞結果:」毛澤東/北/京華煙雲」,一個很奇怪的輸出,跟我們的期望相差較多,但是從中我們可以獲得如下信息:bd分詞可以識別人名,也可以識別」京華煙雲」,這說明有詞典未登錄詞的識別的功能,我們可以假設分詞過程分為兩個階段:第一階段,先查找一個特殊詞典,這個詞典包含一些人名,部分地名以及一些普通詞典沒有的新詞,這樣首先將」毛澤東」解析出來,剩下了字元串」北京華煙雲」,而」北/京華煙雲」,可以看作是反向最大匹配的分詞結果.這樣基本說得通.為了證明這一點,我們提交查詢」發毛澤東北」,我們期望兩種分詞結果,一個是正向最大匹配<發毛,澤,東北>,一個是上述假設的結果<發,毛澤東,北>,事實上bd輸出是第二種情況,這樣基本能確定bd分詞採取了至少兩個詞典,一個是普通詞典,一個是專用詞典().而且是專用詞典先切分,然後將剩餘的片斷交由普通詞典來切分.
繼續測驗,提交查詢」古巴比倫理」,如果是正向最大匹配,那麼結果應該是<古巴比倫,理>,如果是反向最大匹配,那麼結果應該是<古巴,比,倫理>,事實上bd的分詞結果是<古巴比倫,理>,從這個例子看,好像用了正向最大匹配演算法;此外還有一些例子表明好像是使用正向最大匹配的;但是且慢,我們看這個查詢」北京華煙雲」,正向最大匹配期望的結果是<北京,華,煙雲>,而反向最大匹配期望的結果是<北,京華煙雲>,事實上bd輸出的是後者,這說明可能採用的反向最大匹配;從這點我們可以猜測bd採用的是雙向最大匹配分詞演算法,如果正向和反向匹配分詞結果一致當然好辦,直接輸出即可;但是如果兩者不一致,正向匹配一種結果,反向匹配一種結果,此時該如何是好呢?從上面兩個例子看,在這種情況下,bd採取最短路徑方法,也就是切分的片斷越少越好,比如<古巴,比,倫理>和<古巴比倫,理>相比選擇後者,<北京,華,煙雲>和<北,京華煙雲>相比選擇後者.還有類似的一些例子,這樣基本可以解釋這些輸出結果.

② 什麼叫正向最大匹配演算法,反向最大匹配演算法

分詞演算法里的吧

比如 我是一個好人

由於 詞語很多,所以分詞中先設定一個可能的,最長的片語的詞數
比如說,我認定最長的片語是3個字,那在比對中,會將句子3個字為始進行比對
正向匹配演算法好象是從左到右 反向區域演算法是從右到左,具體忘記了

以 「我是一個好人」 為例

正向的順序為
我是一
我是
我 ===> 得到一個詞
是一個
是一
是 ===>得到一個詞
一個好
一個===> 得到一個詞
好人===>得到一個詞
結果 我、是、一個、好人

反向演算法
個好人
好人==> 好人
是一個
一個==> 一個
我是
是==> 是
我==> 我
結果 我、是、一個、好人

java web 怎麼用solr

我們下載的Solr包後,進入Solr所在的目錄,我們可以看到以下幾個目錄:build、client、dist、example、lib、site、src。下面分別對其進行介紹。
1) build:該目錄是在ant build過程中生成的,其中包含了未被打包成jar或是war的class文件以及一些文檔文件。
2) client:該目錄包含了特定語言的Solr客戶端API,使得使用其他語言的用戶能通過HTTP用XML與Solr進行通話。現在該目錄裡面雖然包含javascript、python、ruby三個子目錄,但是到目前為止只包含一部分的ruby的代碼,其他語言仍是空的。另外,Solr的Java客戶端稱為SolrJ,其代碼位於src/solrj目錄下面。在之後的文章中我會詳細介紹Solr客戶端的使用。
3) dist:該目錄包含build過程中產生的war和jar文件,以及相關的依賴文件。還記得上一篇文章中,我們在build 1.4版本的Solr源代碼後需要部署example嗎?其實就是將該目錄下面的apache-solr-1.4.war部署到Jetty上面去,並重命名為solr.war。
4) example:這個目錄實際上是Jetty的安裝目錄。其中包含了一些樣例數據和一些Solr的配置。
其中一些子目錄也比較重要,這里也對它們稍作介紹。
l example/etc:該目錄包含了Jetty的配置,在這里我們可以將Jetty的默認埠從8983改為80埠。
l 將其中的8983埠換成80埠。注意更改埠後啟動Jetty可能會提示你沒有許可權,你需要使用sudo java -jar start.jar來運行。
l example/multicore:該目錄包含了在Solr的multicore中設置的多個home目錄。在之後的文章中我會對其進行介紹。
l example/solr:該目錄是一個包含了默認配置信息的Solr的home目錄。
詳見下面的「solr home說明」
l example/webapps:Jetty的webapps目錄,該目錄通常用來放置Java的Web應用程序。在Solr中,前面提到的solr.war文件就部署在這里。
5) lib:該目錄包含了所有Solr的API所依賴的庫文件。其中包括Lucene,Apache commons utilities和用來處理XML的Stax庫。
6) site:該目錄僅僅包含了Solr的官網的網頁內容,以及一些教程的PDF文檔。
7) src:該目錄包含了Solr項目的整個源代碼。這里對其各個子目錄也做相應的介紹。
l src/java:該目錄存放的是Solr使用Java編寫的源代碼。
l src/scripts:該目錄存放的是配置Solr伺服器的Unix BashShell腳本,在後面介紹多伺服器配置中將會有重要的作用。
l src/solrj:前面提到過該目錄存放的是Solr的Java版本的客戶端代碼。
l src/test:該目錄存放的是測試程序的源代碼和測試文件。
l src/webapp:該目錄存放的是管理Solr的Web頁面,包括Servlet和JSP文件,其構成了前面提到的WAR文件。管理Solr的JSP頁面在web/admin目錄下面,如果你有興趣折騰Solr可以找到相應的JSP的頁面對其進行設置
1.4.2 Solr home說明
所謂的Solr home目錄實際上是一個運行的Solr實例所對應的配置和數據(Lucene索引)。在上一篇文章中我提到過在Solr的example/solr目錄就是一個Solr用做示例的默認配置home目錄。實際上example/multicore也是一個合法的Solr home目錄,只不過是用來做mult-core設置的。那麼我們來看看example/solr這個目錄裡面都有些什麼。
example/solr目錄下主要有以下一些目錄和文件:
1) bin:如果你需要對Solr進行更高級的配置,該目錄建議用來存放Solr的復制腳本。
2) conf :該目錄下麵包含了各種配置文件,下面列出了兩個最為重要的配置文件。其餘的.txt和.xml文件被這兩個文件所引用,如用來對文本進行特殊的處理。
l conf/schema.xml:該文件是索引的schema,包含了域類型的定義以及相關聯的analyzer鏈。
l conf/solrconfig.xml:該文件是Solr的主配置文件。
l conf/xslt:該目錄包含了各種XSLT文件,能將Solr的查詢響應轉換成不同的格式,如:Atom/RSS等。
3) data:包含了Lucene的二進制索引文件。
4) lib:該目錄是可選的。用來放置附加的Java JAR文件,Solr在啟動時會自動載入該目錄下的JAR文件。這就使得用戶可以對Solr的發布版本(solr.war)進行擴展。如果你的擴展並不對Solr本身進行修改,那麼就可以將你的修改部署到JAR文件中放到這里。

Solr是如何找到運行所需要的home目錄的呢?
Solr首先檢查名為solr.solr.home的Java系統屬性,有幾種不同的方式來設置該Java系統屬性。一種不管你使用什麼樣的Java應用伺服器或Servlet引擎都通用的方法是在調用Java的命令行中進行設置。所以,你可以在啟動Jetty的時候顯式地指定Solr的home目錄java -Dsolr.solr.home=solr/ -jar start.jar。另一種通用的方法是使用JNDI,將home目錄綁定到java:comp/env/solr/home。並向src/webapp/web/WEB-INF/web.xml添加以下一段代碼:
1 <env-entry>
2 <env-entry-name>solr/home</env-entry-name>
3 <env-entry-value>solr/</env-entry-value>
4 <env-entry-type>java.lang.String</env-entry-type>
5 </env-entry>
實際上這段XML在web.xml文件中已經存在,你只需要把原來注釋掉的xml取消注釋,添加你所要指向的home目錄即可。因為修改了web.xml文件,所以你需要運行antdist-war來重新打包之後再部署WAR文件。

最後,如果Solr的home目錄既沒有通過Java系統屬性指定也沒有通過JNDI指定,那麼他將默認指向solr/。
在產品環境中,我們必須設置Solr的home目錄而不是讓其默認指向solr/。而且應該使用絕對路徑,而不是相對路徑,因為你有可能從不同的目錄下面啟動應用伺服器。

註:Jetty 是一個開源的servlet容器,它為基於Java的web內容,例如JSP和servlet提供運行環境。Jetty是使用Java語言編寫的,它的API以一組JAR包的形式發布。開發人員可以將Jetty容器實例化成一個對象,可以迅速為一些獨立運行(stand-alone)的Java應用提供網路和web連接。

我們先從使用者的角度出發,最先看到的當然是servlet,因為Solr本身是個獨立的網路應用程序,需要在Servlet容器中運行來提供服務,所以servlet是用戶接觸的最外層。我們看看org.apache.solr.servlet包。這個包很簡單,只有兩個類:SolrServlet和SolrUpdateServlet.我們很容易從類名中猜出這兩個類的用途。
SolrServlet類繼承HttpServlet類,只有四個方法:
· init()
· destroy()
· doGet()
· doPost()
SolrServlet類中除了普通的Java類對象(包括Servlet相關的)外,有四個Solr本身的類,還有一個Solr本身的異常。其中兩個類和一個異常屬於org.apache.solr.core包,兩個類屬於org.apache.solr.request包。屬於core包的有:
· Config:
· SolrCore:
屬於request包的有:
· SolrQueryResponse:
· QueryResponseWriter:
分析一下這個SolrServlet類。首先servlet會調用init()方法進行初始化:通過Context查找java:comp/env/solr/home來確定Solr的主目錄(home),接著調用Config.setInstanceDir(home)方法設置這個實例的目錄。然後通過SolrCore.getSolrCore()來獲得一個SolrCore實例。destroy()方法將會在Servlet對象銷毀時調用,僅僅調用core.close()關閉SolrCore實例。
當用戶請求進來時doPost()簡單地將任務交給doGet()完成,主要的任務由doGet()完成。分析一下doGet()方法:
1) 使用SolrCore和doGet()參數request生成一個SolrServletRequest對象(注意:這個SolrServletRequest類不是公開類,位於org.apache.solr.servlet包中,繼承了SolrQueryRequestBase類,僅僅接受SolrCore和HttpServletRequest對象作為參數)
2) 然後SolrCore執行execute()方法(參數為SolrServletRequest和SolrQueryResponse)
由此可見,真正的處理核心是SolrCore的execute方法

④ 有沒有利用斯坦福自然語言庫處理英文信息的分詞代碼 java

眾所周知,英文是以詞為單位的,詞和詞之間是靠空格隔開,而中文是以字為單位,句子中所有的字連起來才能描述一個意思。例如,英文句子I am a student,用中文則為:「我是一個學生」。計算機可以很簡單通過空格知道student是一個單詞,但是不能很容易明白「學」、「生」兩個字合起來才表示一個詞。把中文的漢字序列切分成有意義的詞,就是中文分詞,有些人也稱為切詞。我是一個學生,分詞的結果是:我 是 一個 學生。
中文分詞技術屬於自然語言處理技術范疇,對於一句話,人可以通過自己的知識來明白哪些是詞,哪些不是詞,但如何讓計算機也能理解?其處理過程就是分詞演算法。

現有的分詞演算法可分為三大類:基於字元串匹配的分詞方法、基於理解的分詞方法和基於統計的分詞方法。

1、基於字元串匹配的分詞方法

這種方法又叫做機械分詞方法,它是按照一定的策略將待分析的漢字串與一個「充分大的」機器詞典中的詞條進行配,若在詞典中找到某個字元串,則匹配成功(識別出一個詞)。按照掃描方向的不同,串匹配分詞方法可以分為正向匹配和逆向匹配;按照不同長度優先匹配的情況,可以分為最大(最長)匹配和最小(最短)匹配;按照是否與詞性標注過程相結合,又可以分為單純分詞方法和分詞與標注相結合的一體化方法。常用的幾種機械分詞方法如下:

1)正向最大匹配法(由左到右的方向);

2)逆向最大匹配法(由右到左的方向);

3)最少切分(使每一句中切出的詞數最小)。

還可以將上述各種方法相互組合,例如,可以將正向最大匹法和逆向最大匹法結合起來構成雙向匹配法。由於漢語單字成詞的特點,正向最小匹配和逆向最小匹配一般很少使用。一般說來,逆向匹配的切分精度略高於正向匹配,遇到的歧義現象也較少。統計結果表明,單純使用正向最大匹配的錯誤率為1/169,單純使用逆向最大匹配的錯誤率為1/245。但這種精度還遠遠不能滿足實際的需要。實際使用的分詞系統,都是把機械分詞作為一種初分手段,還需通過利用各種其它的語言信息來進一步提高切分的准確率。

一種方法是改進掃描方式,稱為特徵掃描或標志切分,優先在待分析字元串中識別和切分出一些帶有明顯特徵的詞,以這些詞作為斷點,可將原字元串分為較小的串再來進機械分詞,從而減少匹配的錯誤率。另一種方法是將分詞和詞類標注結合起來,利用豐富的詞類信息對分詞決策提供幫助,並且在標注過程中又反過來對分詞結果進行檢驗、調整,從而極大地提高切分的准確率。

對於機械分詞方法,可以建立一個一般的模型,在這方面有專業的學術論文,這里不做詳細論述。

2、基於理解的分詞方法

這種分詞方法是通過讓計算機模擬人對句子的理解,達到識別詞的效果。其基本思想就是在分詞的同時進行句法、語義分析,利用句法信息和語義信息來處理歧義現象。它通常包括三個部分:分詞子系統、句法語義子系統、總控部分。在總控部分的協調下,分詞子系統可以獲得有關詞、句子等的句法和語義信息來對分詞歧義進行判斷,即它模擬了人對句子的理解過程。這種分詞方法需要使用大量的語言知識和信息。由於漢語語言知識的籠統、復雜性,難以將各種語言信息組織成機器可直接讀取的形式,因此目前基於理解的分詞系統還處在試驗階段。

3、基於統計的分詞方法

從形式上看,詞是穩定的字的組合,因此在上下文中,相鄰的字同時出現的次數越多,就越有可能構成一個詞。因此字與字相鄰共現的頻率或概率能夠較好的反映成詞的可信度。可以對語料中相鄰共現的各個字的組合的頻度進行統計,計算它們的互現信息。定義兩個字的互現信息,計算兩個漢字X、Y的相鄰共現概率。互現信息體現了漢字之間結合關系的緊密程度。當緊密程度高於某一個閾值時,便可認為此字組可能構成了一個詞。這種方法只需對語料中的字組頻度進行統計,不需要切分詞典,因而又叫做無詞典分詞法或統計取詞方法。但這種方法也有一定的局限性,會經常抽出一些共現頻度高、但並不是詞的常用字組,例如「這一」、「之一」、「有的」、「我的」、「許多的」等,並且對常用詞的識別精度差,時空開銷大。實際應用的統計分詞系統都要使用一部基本的分詞詞典(常用詞詞典)進行串匹配分詞,同時使用統計方法識別一些新的詞,即將串頻統計和串匹配結合起來,既發揮匹配分詞切分速度快、效率高的特點,又利用了無詞典分詞結合上下文識別生詞、自動消除歧義的優點。

到底哪種分詞演算法的准確度更高,目前並無定論。對於任何一個成熟的分詞系統來說,不可能單獨依靠某一種演算法來實現,都需要綜合不同的演算法。筆者了解,海量科技的分詞演算法就採用「復方分詞法」,所謂復方,相當於用中中的復方概念,即用不同的才綜合起來去醫治疾病,同樣,對於中文詞的識別,需要多種演算法來處理不同的問題。

⑤ seo問題,什麼叫正向匹配什麼叫逆向匹配舉例說明

下面牛到家SEO介紹的分詞演算法中最簡單的正向最大匹配和反向最大匹配。

這種兩種方法都是機械分詞方法,它是按照一定的策略將待分析的漢字串與一個」充分大的」機器詞典中的詞條進行配,若在詞典中找到某個字元串,則匹配成功(識別出一個詞)。
按照掃描方向的不同,串匹配分詞方法可以分為正向匹配和逆向匹配;按照不同長度優先匹配的情況,可以分為最大(最長)匹配和最小(最短)匹配;按照是否與詞性標注過程相結合,又可以分為單純分詞方法和分詞與標注相結合的一體化方法。常用的幾種機械分詞方法如下:
1)正向最大匹配法(由左到右的方向);
2)逆向最大匹配法(由右到左的方向);
3)最少切分(使每一句中切出的詞數最小)。
還可以將上述各種方法相互組合,例如,可以將正向最大匹配方法和逆向最大匹配方法結合起來構成雙向匹配法。由於漢語單字成詞的特點,正向最小匹配和逆向最小匹配一般很少使用。一般說來,逆向匹配的切分精度略高於正向匹配,遇到的歧義現象也較少。統計結果表明,單純使用正向最大匹配的錯誤率為1/169,單純使用逆向最大匹配的錯誤率為1/245。但這種精度還遠遠不能滿足實際的需要。實際使用的分詞系統,都是把機械分詞作為一種初分手段,還需通過利用各種其它的語言信息來進一步提高切分的准確率。
一種方法是改進掃描方式,稱為特徵掃描或標志切分,優先在待分析字元串中識別和切分出一些帶有明顯特徵的詞,以這些詞作為斷點,可將原字元串分為較小的串再來進機械分詞,從而減少匹配的錯誤率。另一種方法是將分詞和詞類標注結合起來,利用豐富的詞
類信息對分詞決策提供幫助,並且在標注過程中又反過來對分詞結果進行檢驗、調整,從而極大地提高切分的准確率
定義比較抽象,舉個例子來說明正向最大匹配和反向最大匹配。
例子:』今天來了許多新同事』
1.正向最大匹配方式,最大長度為5
今天來了許
今天來了
今天來
今天 ====》 得到一個詞–今天
來了許多新
來了許多
來了許
來了
來 ====》 得到一個詞–來
了許多新同
了許多新
了許多
了許
了 ====》 得到一個詞–了
許多新同事
許多新同
許多新
許多 ====》得到一個詞– 許多
新同事
新同
新 ====》得到一個詞– 新
同事 ====》得到一個詞– 同事
最後正向最大匹配的結果是:
/今天/來/了/許多/新/同事/
2.反向最大匹配方式,最大長度為5
許多新同事
多新同事
新同事
同事 ====》得到一個詞– 同事
來了許多新
了許多新
許多新
多新
新 ====》得到一個詞– 新
天來了許多
來了許多
了許多
許多 ====》得到一個詞– 許多
今天來了
天來了
來了
了 ====》得到一個詞– 了
今天來
天來
來 ====》得到一個詞– 來
今天 ====》得到一個詞– 今天
最後反向最大匹配的結果是:
/今天/來/了/許多/新/同事/
正向最大匹配和反向最大匹配的結果並不一定相同
例子:』我一個人吃飯』
1.正向最大匹配方式,最大長度為5
我一個人吃
我一個人
我一個
我一
我 ====》得到一個詞– 我
一個人吃飯
一個人吃
一個人
一個 ====》得到一個詞– 一個
人吃飯
人吃
人 ====》得到一個詞– 人
吃飯 ====》得到一個詞– 吃飯
最後正向最大匹配的結果是:
/我/一個/人/吃飯/
2.反向最大匹配方式,最大長度為5
一個人吃飯
個人吃飯
人吃飯
吃飯 ====》得到一個詞– 吃飯
我一個人
一個人
個人 ====》得到一個詞– 個人
我一
一 ====》得到一個詞– 一
我 ====》得到一個詞– 我
最後反向最大匹配的結果是:
/我/一/個人/吃飯/
這次兩種方式的結果就不一致了。更多SEO知識請網路搜牛到家SEO

⑥ 中文分詞中正向最大匹配演算法的分詞速度是多少准確率大概為多少

主要看你的詞表結構了,最大詞長的初始值,查詞典的次數和匹配的次數,然後得出時間復雜度,原始hash演算法復雜度沒記錯的話應該是2.89,11年看過一個文獻,提出一種改進的演算法時間復雜度是2.291……

另外,分詞演算法並不是原封不動的,比如有些搜索引擎的詞表結構就採用tire樹結構,這樣不用設置最大詞長,不過內存空間方面就要有取捨,甚至還有採用減少查典次數增加匹配次數的搜索引擎……
所以單純的給你一個189.3m/M純內存分詞速度,但是這演算法換個台更高配置的伺服器卻變成了497.6ms/M,這沒有任何意義……
記得哪個文獻上有人說,分詞本身不是目的,而是後續處理過程的必要階段,所以,除非你是研究演算法的,否則單純追求這東西的速度和准確率沒什麼太大意義

⑦ 定義五個數字,獲取這五個數字中最大值,並輸出最大值的絕對值。

本文是對整段話進行分詞,首先將這段話根據標點符號斷句,然後將每句話再進行分詞輸出。
?


package cn.nwsuaf.spilt;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Scanner;/** * 基於正逆雙向最大匹配分詞演算法實現 * @author 劉永浪 * */public class WordSpilt { /** * 存儲分詞詞典 */ private Map<String, Integer> map = new HashMap<String, Integer>(); /** * 最大切詞長度,即為五個漢字 */ private int MAX_LENGTH = 5; /** * 構造方法中讀取分詞詞典,並存儲到map中 * * @throws IOException */ public WordSpilt() throws IOException { BufferedReader br = new BufferedReader(new FileReader("src/dict.txt")); String line = null; while ((line = br.readLine()) != null) { line = line.trim(); map.put(line, 0); } br.close(); } /** * 設置最大切詞長度 * * @param max * 最大切詞長度 */ public void setMaxLength(int max) { this.MAX_LENGTH = max; } /** * 獲取當前最大切詞長度,默認為5(5個漢字) * * @return 當前最大切詞長度 */ public int getMaxLength() { return this.MAX_LENGTH; } /** * 最大匹配分詞演算法 * * @param spiltStr * 待切分的字元串 * @param leftToRight * 切分方向,true為從左向右,false為從右向左 * @return 切分的字元串 */ public List<String> spilt(String spiltStr, boolean leftToRight) { // 如果帶切分字元串為空則返回空 if (spiltStr.isEmpty()) return null; // 儲存正向匹配分割字元串 List<String> leftWords = new ArrayList<String>(); // 儲存負向匹配分割字元串 List<String> rightWords = new ArrayList<String>(); // 用於取切分的字串 String word = null; // 取詞的長度,初始化設置為最大值 int wordLength = MAX_LENGTH; // 分詞操作中處於字串當前位置 int position = 0; // 已經處理字元串的長度 int length = 0; // 去掉字元串中多餘的空格 spiltStr = spiltStr.trim().replaceAll("\\s+", ""); // 當待切分字元串沒有被切分完時循環切分 while (length < spiltStr.length()) { // 如果還沒切分的字元串長度小於最大值,讓取詞詞長等於該詞本身長度 if (spiltStr.length() - length < MAX_LENGTH) wordLength = spiltStr.length() - length; // 否則取默認值 else wordLength = MAX_LENGTH; // 如果是正向最大匹配,從spiltStr的position處開始切割 if (leftToRight) { position = length; word = spiltStr.substring(position, position + wordLength); } // 如果是逆向最大匹配,從spiltStr末尾開始切割 else { position = spiltStr.length() - length; word = spiltStr.substring(position - wordLength, position); } // 從當前位置開始切割指定長度的字元串 // word = spiltStr.substring(position, position + wordLength); // 如果分詞詞典裡面沒有切割出來的字元串,捨去一個字元 while (!map.containsKey(word)) { // 如果是單字,退出循環 if (word.length() == 1) { // 如果是字母或是數字要將連續的字母或者數字分在一起 if (word.matches("[a-zA-z0-9]")) { // 如果是正向匹配直接循環將後續連續字元加起來 if (leftToRight) { for (int i = spiltStr.indexOf(word, position) + 1; i < spiltStr .length(); i++) { if ((spiltStr.charAt(i) >= '0' && spiltStr .charAt(i) <= '9') || (spiltStr.charAt(i) >= 'A' && spiltStr .charAt(i) <= 'Z') || (spiltStr.charAt(i) >= 'a' && spiltStr .charAt(i) <= 'z')) { word += spiltStr.charAt(i); } else break; } } else { // 如果是逆向匹配,從當前位置之前的連續數字、字母字元加起來並翻轉 for (int i = spiltStr.indexOf(word, position - 1) - 1; i >= 0; i--) { if ((spiltStr.charAt(i) >= '0' && spiltStr .charAt(i) <= '9') || (spiltStr.charAt(i) >= 'A' && spiltStr .charAt(i) <= 'Z') || (spiltStr.charAt(i) >= 'a' && spiltStr .charAt(i) <= 'z')) { word += spiltStr.charAt(i); if (i == 0) { StringBuffer sb = new StringBuffer(word); word = sb.reverse().toString(); } } else { // 翻轉操作 StringBuffer sb = new StringBuffer(word); word = sb.reverse().toString(); break; } } } } break; } // 如果是正向最大匹配,捨去最後一個字元 if (leftToRight) word = word.substring(0, word.length() - 1); // 否則捨去第一個字元 else word = word.substring(1); } // 將切分出來的字元串存到指定的表中 if (leftToRight) leftWords.add(word); else rightWords.add(word); // 已處理字元串增加 length += word.length(); } // 如果是逆向最大匹配,要把表中的字元串調整為正向 if (!leftToRight) { for (int i = rightWords.size() - 1; i >= 0; i--) { leftWords.add(rightWords.get(i)); } } // 返回切分結果 return leftWords; } /** * 判斷兩個集合是否相等 * * @param list1 * 集合1 * @param list2 * 集合2 * @return 如果相等則返回true,否則為false */ public boolean isEqual(List<String> list1, List<String> list2) { if (list1.isEmpty() && list2.isEmpty()) return false; if (list1.size() != list2.size()) return false; for (int i = 0; i < list1.size(); i++) { if (!list1.get(i).equals(list2.get(i))) return false; } return true; } /** * 判別分詞歧義函數 * * @param inputStr * 待切分字元串 * @return 分詞結果 */ public List<String> resultWord(String inputStr) { // 分詞結果 List<String> result = new ArrayList<String>(); // 「左貪吃蛇」分詞結果 List<String> resultLeft = new ArrayList<String>(); // 「中貪吃蛇」(分歧部分)分詞結果 List<String> resultMiddle = new ArrayList<String>(); // 「右貪吃蛇」分詞結果 List<String> resultRight = new ArrayList<String>(); // 正向最大匹配分詞結果 List<String> left = new ArrayList<String>(); // 逆向最大匹配分詞結果 List<String> right = new ArrayList<String>(); left = spilt(inputStr, true); /*System.out.println("正向分詞結果:"); for (String string : left) { System.out.print(string + "/"); } System.out.println("\n逆向分詞結果:");*/ right = spilt(inputStr, false); /*for (String string : right) { System.out.print(string + "/"); } System.out.println("\n雙向分詞結果:");*/ // 判斷兩頭的分詞拼接,是否已經在輸入字元串的中間交匯,只要沒有交匯,就不停循環 while (left.get(0).length() + right.get(right.size() - 1).length() < inputStr .length()) { // 如果正逆向分詞結果相等,那麼取正向結果跳出循環 if (isEqual(left, right)) { resultMiddle = left; break; } // 如果正反向分詞結果不同,則取分詞數量較少的那個,不用再循環 if (left.size() != right.size()) { resultMiddle = left.size() < right.size() ? left : right; break; } // 如果以上條件都不符合,那麼實行「貪吃蛇」演算法 // 讓「左貪吃蛇」吃下正向分詞結果的第一個詞 resultLeft.add(left.get(0)); // 讓「右貪吃蛇」吃下逆向分詞結果的最後一個詞 resultRight.add(right.get(right.size() - 1)); // 去掉被「貪吃蛇」吃掉的詞語 inputStr = inputStr.substring(left.get(0).length()); inputStr = inputStr.substring(0, inputStr.length() - right.get(right.size() - 1).length()); // 清理之前正逆向分詞結果,防止造成干擾 left.clear(); right.clear(); // 對沒被吃掉的字元串重新開始分詞 left = spilt(inputStr, true); right = spilt(inputStr, false); } // 循環結束,說明要麼分詞沒有歧義了,要麼"貪吃蛇"從兩頭吃到中間交匯了 // 如果是在中間交匯,交匯時的分詞結果,還要進行以下判斷: // 如果中間交匯有重疊了: // 正向第一個分詞的長度 + 反向最後一個分詞的長度 > 輸入字元串總長度,就直接取正向的 if (left.get(0).length() + right.get(right.size() - 1).length() > inputStr .length()) resultMiddle = left; // 如果中間交匯,剛好吃完,沒有重疊: // 正向第一個分詞 + 反向最後一個分詞的長度 = 輸入字元串總長度,那麼正反向一拼即可 if (left.get(0).length() + right.get(right.size() - 1).length() == inputStr .length()) { resultMiddle.add(left.get(0)); resultMiddle.add(right.get(right.size() - 1)); } // 將沒有歧義的分詞結果添加到最終結果result中 for (String string : resultLeft) { result.add(string); } for (String string : resultMiddle) { result.add(string); } // 「右貪吃蛇」存儲的分詞要調整為正向 for (int i = resultRight.size() - 1; i >= 0; i--) { result.add(resultRight.get(i)); } return result; } /** * 將一段話分割成若干句話,分別進行分詞 * * @param inputStr * 待分割的一段話 * @return 這段話的分詞結果 */ public List<String> resultSpilt(String inputStr) { // 用於存儲最終分詞結果 List<String> result = new ArrayList<String>(); // 如果遇到標點就分割成若干句話 String regex = "[,。;!?]"; String[] st = inputStr.split(regex); // 將每一句話的分詞結果添加到最終分詞結果中 for (String stri : st) { List<String> list = resultWord(stri); result.addAll(list); } return result; } public static void main(String[] args) { // example:過來看房價貴不貴?乒乓球拍賣完了 Scanner input = new Scanner(System.in); String str = input.nextLine(); WordSpilt wordSpilt = null; try { wordSpilt = new WordSpilt(); } catch (IOException e) { e.printStackTrace(); } List<String> list = wordSpilt.resultWord(str); for (String string : list) { System.out.print(string + "/"); } }}

⑧ 求 JAVA 字元串匹配 完美演算法

只需要實例化 類Matching 設置參數 並調用m.getIndex()方法就OK 請測試... public class Test18{

public static void main(String[] args){
Matching m = new Matching();
m.setOrgStr("ALSKLSHFKDLLS");
m.setSubStr("LS");
System.out.println(m.getIndex());

}
}
class Matching{

String orgStr ="";
String subStr ="";

public void setOrgStr(String orgStr){
this.orgStr = orgStr;
}

public void setSubStr(String subStr){
this.subStr = subStr;
}

public String getIndex(){

StringBuffer sb = new StringBuffer("{");

//根據關鍵字subStr來拆分字元串orgStr所得的字元串數組
String[] sub = orgStr.split(subStr);

int keyLength = subStr.length(); //關鍵字長度
int keySize = 0; //關鍵字個數

int subSize = sub.length; //子字元串個數
int subLength = 0; //子字元串長度

if(!orgStr.endsWith(subStr)){
keySize = subSize-1;
}else
keySize = subSize; int[] index = new int[keySize];//關鍵字下標數組
for(int i=0;i<keySize;i++){
subLength = sub[i].length();
if(i==0){
index[i]=subLength;
}else
index[i]=index[i-1]+subLength+keyLength;
}

if(keySize>0){
int l = keySize-1;
for(int i=0;i<l;i++){
sb.append(index[i]+",");
}
sb.append(index[l]);//最後一個關鍵字下標
}else{
sb.append("NULL");
}
sb.append("}");

return sb.toString();
}

}

閱讀全文

與java正向最大匹配演算法相關的資料

熱點內容
汽車小壓縮機拆解 瀏覽:825
雲桌面卡是因為伺服器的原因嗎 瀏覽:377
qd123壓縮機 瀏覽:969
pn532讀取加密門禁卡 瀏覽:85
win10文件夾屬性里無法加密 瀏覽:34
比特幣加密的條件 瀏覽:848
求購現成影視app源碼 瀏覽:572
wdsecurity加密版 瀏覽:813
雲伺服器和雲豐雲 瀏覽:188
伺服器如何設置獨立ip 瀏覽:857
tar命令打包文件夾 瀏覽:1000
刪除linux用戶和組 瀏覽:548
小米的程序員都用什麼筆記本 瀏覽:703
位元組三面演算法題 瀏覽:971
伺服器保護有什麼好處 瀏覽:894
全部下載完後進行統一解壓 瀏覽:393
遠嫁的程序員媽媽 瀏覽:555
1024程序員節安全攻防挑戰賽 瀏覽:786
怎麼解除txt加密 瀏覽:772
javahttp流 瀏覽:656