UWInfo Blog
發表新文章
[Join] | [忘記密碼] | [Login]
搜尋

搜尋意見
文章分類-#Author#
[所有文章分類]
所有文章分類
  • ASP.NET (48)
  • ASP.NET2.0 (15)
  • ASP.NET4.0 (34)
  • JavaScript (49)
  • jQuery (26)
  • FireFox (4)
  • UW系統設定 (3)
  • SQL (39)
  • SQL 2008 (25)
  • mirror (4)
  • SVN (4)
  • IE (9)
  • IIS (20)
  • IIS6 (1)
  • 閒聊 (7)
  • W3C (6)
  • 作業系統 (9)
  • C# (24)
  • CSS (12)
  • FileServer (1)
  • HTML 5 (11)
  • CKEditor (3)
  • UW.dll (13)
  • Visual Studio (16)
  • Browser (8)
  • SEO (1)
  • Google Apps (3)
  • 網站輔助系統 (4)
  • DNS (5)
  • SMTP (4)
  • 網管 (11)
  • 社群API (3)
  • SSL (4)
  • App_Inventor (1)
  • URLRewrite (2)
  • 開發工具 (6)
  • JSON (1)
  • Excel2007 (1)
  • 試題 (3)
  • LINQ (1)
  • bootstrap (0)
  • Vue (3)
  • IIS7 (3)
  • foodpanda (2)
  • 編碼 (2)
  • 資安 (3)
  • Sourcetree (1)
  • MAUI (1)
  • CMD (1)
  • my sql (1)
最新回應
  • Newtonsoft.Json.JsonConvert.DeserializeObject 失敗的情況
    test...more
  • dotnet ef dbcontext scaffold
    ...more
  • [ASP.NET] 利用 aspnet_regiis 加密 web.config
    ...more
  • IIS ARR (reverse proxy) 服務安裝
    ...more
  • [錯誤訊息] 請加入 ScriptResourceMapping 命名的 jquery (區分大小寫)
    ...more
  • 用 Javascript 跨網頁讀取 cookie (Cookie cross page, path of cookie)
    ...more
  • 線上客服 - MSN
    本人信箱被盜用以致資料外洩,是否可以請貴平台予以協助刪除該信箱之使用謝謝囉...more
  • 插入文字到游標或選取處
    aaaaa...more
  • IIS 配合 AD (Active Directory) 認証, 使用 .Net 6.0
    太感謝你了~~~你救了我被windows 認證卡了好幾天QQ...more
  • PostgreSQL 的 monitor trigger
    FOR EACH ROW 可能要改為 FOR EACH STATEMENT ...more
標籤
  • tim
  • GN
  • WU
  • editor
  • SqlCacheDe
  • 光
  • pG2rL0AN
  • 1
  • cros
  • 方案總管
  • window
  • Rf
  • AD
  • [t]
  • entify
  • 有潛在危險 Requ
  • exception
  • sa
  • date[t] OR
  • -5688 UNIO
  • 上傳檔案太大
  • attr
  • [u2]
  • c
  • aJkc4exf
  • User
  • EN
  • 0
  • max2121121
  • 檔案
  • SQL 授權
  • @@YOTU3
  • request
  • 2515
  • 6593
  • ?
  • 403 -
  • Cache
  • dttoexcel2
  • nexttick
  • mibs
  • web
  • 手機版網頁
  • dotnet
  • array
  • orm
  • FireFox
  • jq
  • 7463
  • gn.linepay
頁數 2 / 3 上一頁 下一頁
搜尋 結果:
使用Lucene.Net達成全文檢索!基礎解說(一)
Lucene.Net是一套C#開源全文索引庫,其主要包含了:
· Index : 提供索引的管理與詞組的排序
· Search : 提供查詢相關功能
· Store : 支援資料儲存管理,包括I/O操作
· Util : 共用套件
· Documents : 負責描述索引儲存時的文件結構管理
· QueryParsers : 提供查詢語法
· Analysis : 負責分析內容
要達到高效能的全文檢索讓機器可以明白我們的語言,最重要的關鍵就是"分詞器"了。
試想一下這一句話你會如何拆分成一段一段的關鍵字呢?
"一天一蘋果,醫生遠離我"
還有英文版本
"An apple a day, doctor keep me away."
中文版本的拆分:
"一天"、"一"、"蘋果"、"醫生"、"遠離"、"我"
英文版本的拆分:
"apple"、"day"、"doctor"、"keep"、"me"、"away"
有沒有注意到不同語系所分析出來的關鍵字有一點不一樣呢?
而在Lucene中分詞的工作會交給Analysis來完成,
不過我們可以依照不同的語系去選擇想使用的分詞器(Analyzer)!

首先簡單說明一下Lucene的實作流程
1. 確認主要搜尋的語系來決定使用的分詞器(analyzer)
2. 建立Document依照analyzer匯入資料
(前置完成)
3. 建立IndexSearcher導入準備好的Document
4. 建立Parser來分析SearchValue
5. 使用IndexSearcher分析Parser取得結果(Hits)
*本專案使用的是Lucene.Net 3.0.3*
接下來我們來建立一個提供查詢使用的Document。

       
 // 取得或建立Lucene文件資料夾
        if (!File.Exists(_dir.FullName))
        {
            System.IO.Directory.CreateDirectory(_dir.FullName);
        }
        // Asp.Net Core需要於Nuget安裝System.Configuration.ConfigurationManager提供用戶端應用程式的組態檔存取
        Lucene.Net.Store.Directory directory = FSDirectory.Open(_dir);
        // 選擇分詞器
        var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_CURRENT);
        // 資料來源
        var repository = new Repository();
        // 依照指定的文件結構來建立
        var indexWriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
        foreach (var index in repository)
        {
            var document = new Document();
            document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));
            document.Add(new Field("Name", index.Name, Field.Store.YES, Field.Index.ANALYZED));
            document.Add(new Field("Description", index.Description, Field.Store.NO, Field.Index.ANALYZED));
            indexWriter.AddDocument(document);
        }
        indexWriter.Optimize();
        indexWriter.Commit();
        indexWriter.Dispose();


如此一來我們就建立好Lucene的基本配備囉!
其中analyzer的部分我們使用Lucene.Net預設,
要特別注意的是,其處理中文語系的能力非常之爛!
之後再寫一篇文章深入探討。
再來值得一提的是
       
document.Add(new Field("Id", index.Id.ToString(), Field.Store.YES, Field.Index.NO));

前兩個參數就是Key跟Value,可以簡單理解為欄位與其內容。
後面兩個參數是重點!
Store: 代表是否儲存這個Key的Value
例如在google打上台南美食會搜索出許多不同的文章連結,
不過google給你的資料中最重要的不是文章內容(Description),
而是哪一篇文章(Name)與台南美食最有關係。
假如今天我只要回傳一個列表而不用提示文章中有哪些內容,
那麼我就可以選擇給"Description" Field.Store.No來節省空間。
Index:
· NO - 不加入索引,這個內容只需要隨著結果出爐,不需要在查詢的時候被考慮。
· ANALYZED、NOT_ANALYZED - 是否使用分詞
· NO_NORMS - 關閉權重功能
或許許多人會對權重功能(NORMS)感到疑惑,
簡單的舉個例子
{ Id=1, Key="蘋果", Value="一天一蘋果,醫生遠離我。"}
{ Id=2, Key="橘子", Value="醫生給娜美最珍貴的寶藏。"}
{ Id=3, Key="梨子", Value="我是梨子,比蘋果蘋果好吃多囉!"}
當我搜尋"蘋果"的時候結果會是
{ Id=1, MatchKey=1, MatchValue=1, Score=(1*5) + (1*2) = 7}
{ Id=3, MatchKey=0, MatchValue=1, Score=(0*5) + (2*2) = 4}
有發現了嗎?
雖然同樣都對中兩個結果但是Id 1的資料Key值中有包含關鍵字,
因此得到較高的分數排在Id 3前方
準備好Document了,我們可以開始來實際使用看看囉!

       
// 決定所要搜索的欄位
        var parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_CURRENT, "Description", analyzer).Parse(searchValue);
        // 提供剛剛建立的Document
        var indexSearcher = new IndexSearcher(directory);
        // 搜尋取出結果的數量
        var queryLimit = 20;
        // 開始搜尋!
        var hits = indexSearcher.Search(parser, queryLimit);
        if (!hits.ScoreDocs.Any())
        {
            Console.WriteLine("查無相關結果。");
            return;
        }
        Document doc;
        foreach (var hit in hits.ScoreDocs)
        {
            doc = indexSearcher.Doc(hit.Doc);
            Console.WriteLine("Score :" + hit.Score + ", Id :" + doc.Get("Id") + ", Name :" + doc.Get("Name") + ", Description :" + doc.Get("Description"));
        }


最後的結果(Hits),是需要再回到Document去撈出對應的資料喔!
是不是非常簡單呢?
筆者寫了一個簡單的範例在GitHub上,秉持著追求新技術的心使用了.Net 6,還請各位大大多多包涵。
有中英文兩種Repository,只需要在上方的DI注入切換就可以囉!
GitHub連結: https://github.com/g13579112000/Lucene
筆者第一次撰寫這種教學文章,有哪邊錯誤的非常歡迎一起來討論指教。
之後有機會再撰寫Lucene更深入的應用方面,
例如權重的分配與分詞器的選擇與使用。
感謝您的閱讀。


參考文獻:
1.黑暗大大的全文檢索筆記: https://blog.darkthread.net/blog/lucene-net-notes-1/
2.使用.Net實現全文檢索: https://blog.csdn.net/huwei2003/article/details/53408388
3.伊凡的部落格: http://irfen.me/5-lucene4-9-learning-record-lucene-analysis-tokenizer/
4.純淨天空代碼範例: https://vimsky.com/zh-tw/examples/detail/csharp-ex-Lucene.Net.Documents-Document---class.html
More...
梨子, 2022/2/24 下午 08:23:46
無法產生 ActiveX 控制項 '8856f961-340a-11d0-a96b-00c04fd705a2',因為目前的執行緒不是在單一執行緒 Apartment
C# PrintScreen to file

出現錯誤: 無法產生 ActiveX 控制項 '8856f961-340a-11d0-a96b-00c04fd705a2',因為目前的執行緒不是在單一執行緒 Apartment。
 
解決方法: 
@Page 加上 AspCompat="true" 即可。
強迫網頁由 STA 執行緒集區服務
More...
Reiko, 2020/9/4 上午 11:54:39
zero-width space
寫程式這麼多年,終於被這個東西給害到,所以特別提一下
zero-width space: 就是沒有寬度的空白,字元碼  \u200b , 或是 urlencode =  %e2%80%8b
當你從 word , excel ,PDF 複製文字貼到記事本,網頁textbox, 或是 visual studio
有時候會把這個碼也一起貼上,重點是: 你肉眼根本看不出來

​2017-08-15 22:05:15​ -> 2017前面有 \u200b, 尾巴也有 
2017-08-15 22:05:15 -> 這個就正常

這會造成甚麼,DateTime.Parse 就會出錯,或是對字串做 MD5 hash 會造成錯誤的結果
然後就會一直 debug 找不出原因,要用 urlencode 測看看才會現出原形
另外,這個碼也無法用 Trim() 清掉,因為他不是 Char.IsWhiteSpace 成員

所以,從 word excel pdf 或是其他網頁 copy 文字貼到程式碼做測試
如果發生怪怪的bug,可能要思考一下是不是這個字元在作怪
More...
darren, 2018/7/19 下午 12:08:41
網站同時使用 C# 與 VB.net
由於早期網站都是VB.net寫的,若是直接換成 C#,就會耗費很多時間在轉換程式上
因此 ASP.NET 特別可以在同一網站同時寫 vb 跟 C#,方式是在 web.config compilation 加上設定
    <compilation debug="true" defaultLanguage="c#" targetFramework="4.0">
     <codeSubDirectories>
        <add directoryName="VB_Code"/>
        <add directoryName="CS_Code"/>
     </codeSubDirectories>
    </compilation>

也就是 VB.NET 的 code 就放到 ~\APP_Code\VB_Code 目錄
C# 的 code 就放到 ~\APP_Code\CS_Code 目錄
這樣做有兩點要注意
1.  Namespace 的命名,最好不要互相衝突, 要能夠區分出來
2.  VB_Code 與 CS_Code 放的位置有很大的影響, 因為牽涉到 compiler的先後順序,因為 VB_Code 在 CS_Code 在前面,所以 CS_Code可以叫用 VB_Code下的程式,但是 VB_Code 卻不能叫用 CS_Code 的程式,如果希望 VB_Code可以叫用 CS_Code的程式,就把設定換過來
    <compilation debug="true" defaultLanguage="c#" targetFramework="4.0">
     <codeSubDirectories>
        <add directoryName="CS_Code"/>
<add directoryName="VB_Code"/>
     </codeSubDirectories>
    </compilation>

缺點就是反過來 CS_Code不能使用 VB_Code的程式

基本上,若是舊的程式碼都在VB_Code 那就把 VB_Code 放到前面
More...
darren, 2017/5/10 下午 02:21:54
C# 下拉選單AutoPostBack後Button點擊沒反應
改用javascript送出
<asp:Button ID="BtnSubmit" runat="server" Text="修改" OnClick="BtnSubmit_Click" OnClientClick="return formSubmit('true');" />


<script type="text/javascript">
                function formSubmit(val) {
                    if (val== "true")
                    {
                        form1.submit();
                    } else {
                        return false;
                    }
                }
            </script>


相關專案: 光寶
More...
Reiko, 2015/6/29 下午 03:49:57
C# difference between `==` and .Equals()
這可能是老問題了,但還是提醒一下
當用  (Object == Object) 比較時,是用 System.Object.ReferenceEquals
所以即使兩個值是一樣的,因為 reference 是不同物件, 他還是會回傳 false
http://stackoverflow.com/questions/814878/c-sharp-difference-between-and-equals

例如要比較一個 datarow 兩個欄位值

row["SDate"] = "2015-04-01";
row["EDate"] = "2015-04-01";

(row["SDate"] == row["EDate"]) ==> false
(row["SDate"].Equals(row["EDate"])) ==> true
(row["SDate"].ToString() == row["EDate"].ToString()) ==> true
More...
darren, 2015/4/14 下午 03:16:40
IsNumeric 以及 Convert.ToInt32(char) 要注意的狀況
最近做一些int型別轉換的時候,發現一些現象,以後寫code的時候要注意

1. VB.NET IsNumeric 用逗號可以過,例如 IsNumeric("1234,5678") ==> True
   但是轉型別 CInt or Convert.ToInt32 就會出錯,所以用 IsNumeric 不是很保險,最好用 int.TryParse

2. Convert.ToInt32(char) 會抓出該 char 的 ascii code, 而不是該文字代表的數字
   Convert.ToInt32('9') ==> 57  (C# 用單引號代表是 char)
   Convert.ToInt32("9") ==> 9
   Convert.ToInt32('A') ==> 65  (C# 用單引號代表是 char)
   Convert.ToInt32("A") ==> error: 輸入字串格式不正確。
More...
darren, 2014/10/28 下午 07:10:28
Optional 參數使用 Date 格式所使用的預設值
VB.NET 時間類別因為沿襲自 VB,所以可以用 Date 型別宣告時間變數
實際上在 .NET 他等於 System.DateTime (C# 沒有 Date型別, 只有System.DateTime)
VB.NET 的 Date 可以設定常數,例如 #12/30/2014# (注意!格式是 MM/dd/yyyy, 用 #包起來),這是C#沒有的 
VB.NET 的 Date 也可以等於 Nothing (Nothing = #12:00:00 AM#)
C# 的 DateTime 可以指定為 default(DateTime) 但是不能 = null

由於 optional 參數必須指定預設值,因此當使用 Date 當作 optional 參數時就要設定以上說的值


Public Sub AddNewCustomer(customer As Customer, Optional dateAdded As Date = Nothing)
     If dateAdded = Nothing Then dateAdded = Now


// C# 4.0 以後的 function 已經可以使用 optional 參數
public void AddNewCustomer(Customer customer, DateTime dateAdded = default(DateTime))
     {
         if (dateAdded == default(DateTime)) dateAdded = DateTime.Now;
         ......


Public Sub AddNewCustomer(customer As Customer, Optional dateAdded As Date = #12/30/1899#)

 
More...
darren, 2014/4/1 下午 02:07:31
List.Find - 找出 List 裡符合條件的資料
從 List<T> 找出符合條件的資料


        List<DB.Member> listOfMember = new List<DB.Member>()
                { new DB.Member(15), new DB.Member(20), new DB.Member(25), new DB.Member(30) };

        // Exists: 單純看有無符合條件的資料
        bool IsMemberExists = listOfMember.Exists(x => x.Email == "darren@acaciaco.com");
        // FindIndex: 找出第一個符合條件的 index,找不到傳回 -1
        int index = listOfMember.FindIndex(x => x.Email == "darren@acaciaco.com");
        // Find: return 第一個符合條件的object, 找不到傳回 null
        DB.Member objMember = listOfMember.Find(x => x.Email.Contains("acaciaco.com"));
        // FindAll: return 所有符合條件的objects
        List<DB.Member> listOfMember2 = listOfMember.FindAll(x => x.Email.Contains("acaciaco.com"));


VB

Dim listOfMember As New List(Of DB.Member)() From { _
    New DB.Member(15), New DB.Member(20), New DB.Member(25), New DB.Member(30) }

' Exists: 單純看有無符合條件的資料
Dim IsMemberExists As Boolean = listOfMember.Exists(Function(x) x.Email = "darren@acaciaco.com")
' FindIndex: 找出第一個符合條件的 index,找不到傳回 -1
Dim index As Integer = listOfMember.FindIndex(Function(x) x.Email = "darren@acaciaco.com")
' Find: return 第一個符合條件的object, 找不到傳回 Nothing
Dim objMember As DB.Member = listOfMember.Find(Function(x) x.Email.Contains("acaciaco.com"))
' FindAll: return 所有符合條件的objects
Dim listOfMember2 As List(Of DB.Member) = listOfMember.FindAll(Function(x) x.Email.Contains("acaciaco.com"))
More...
darren, 2014/3/26 上午 09:43:39
C# Replace 字串不分大小寫
今天遇到關鍵字搜尋後,要把搜尋結果文章內的關鍵字 highlight 起來
結果 string Replace 功能是 case-sensitive, 也就是大小寫有別

查了一下 發現可以用 RegExp.Replace 來處理

return Regex.Replace(strInput, keyword,
    "<span class='highlight'>$0</span>", RegexOptions.IgnoreCase);

其中 $0 就是原來要取代的文字
 
More...
darren, 2012/10/25 下午 02:48:16
|< 123 >|
頁數 2 / 3 上一頁 下一頁
~ Uwinfo ~