• 使用Lucene.net提升网站搜索速度整合记录


    使用Lucene.net提升网站搜索速度整合记录

     

    1.随着网站数据量达到500万条的时候,发现SQL数据库如果使用LIKE语句来查询,总是占用CPU很忙,不管怎么优化,速度还是上不来;

    2.经过网上收集资料,HUBBLE.net目前虽然做得不错,但需要配置内存给他,由于服务器4G内存,而且运行了好几个网站,所以考虑采用Lucene.net来做为搜索引擎;

    3.虽然本地测试没有问题,但是部署到64位的服务器上还是经过了好几天的折腾,在此都记录一下.

    在此记录搜片神器的整个开发过程中遇到的问题和相关的解决方案,希望大家一起交流. 

    Lucene软件下载编译整合的问题                                          

    网站采用了最新Lucene.Net.3.0.3版本的代码,然后配置盘古分词来进行.

    由于Lucene.Net升级到了3.0.3后接口发生了很大变化,原来好多分词库都不能用了,

    .Net下还有一个盘古分词(http://pangusegment.codeplex.com/),但也不支持Lucene.Net 3.0.3,园子里的大哥们修改的项目地址:

    https://github.com/JimLiu/Lucene.Net.Analysis.PanGu

    下载后里面有DEMO代码进行整合.

    Lucene在软件中集成处理                                          

    由于实时处理数据程序是WINFORM程序,所以需要采用软件代码来实时更新索引数据,这样可控性高一些.

    引用头文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    using Lucene.Net.Analysis;
    using Lucene.Net.Analysis.Standard;
    using Lucene.Net.Documents;
    using Lucene.Net.Index;
    using Lucene.Net.QueryParsers;
    using Lucene.Net.Search;
    using Lucene.Net.Store;
    using Lucene.Net.Util;
    using PanGu;
    using Lucene.Net.Analysis.PanGu;
    using PanGu.HighLight;
    using FSDirectory = Lucene.Net.Store.FSDirectory;
    using Version = Lucene.Net.Util.Version;

      

    创建索引

    public static class H31Index
    {
    private static Analyzer analyzer = new PanGuAnalyzer(); //MMSegAnalyzer //StandardAnalyzer
    private static int ONEPAGENUM = 200;
    private static string m_indexPath = "";
    private static IndexWriter iw = null;
    public static void Init(string indexpath)
    {
    m_indexPath = indexpath;
    }

    public static bool OpenIndex()
    {
    try
    {

    DirectoryInfo INDEX_DIR = new DirectoryInfo(m_indexPath+"//Index");
    bool iscreate = true;
    if (INDEX_DIR.Exists)
    iscreate = false;
    Int32 time21 = System.Environment.TickCount;
    if (iw == null)
    {
    iw = new IndexWriter(FSDirectory.Open(INDEX_DIR), analyzer, iscreate, new IndexWriter.MaxFieldLength(32));
    Int32 time22 = System.Environment.TickCount;
    H31Debug.PrintLn("IndexWriter2[" + type.ToString() + "]:" + " IndexWriter:" + (time22 - time21).ToString() + "ms");
    return true;
    }
    }
    catch (System.Exception ex)
    {
    H31Debug.PrintLn("OpenIndex" + ex.Message);
    }
    return false;
    }

    public static void CloseIndex()
    {
    try
    {
    if (iw != null)
    {
    //if (count > 0)
    {
    iw.Commit();
    iw.Optimize();
    }
    iw.Dispose();
    iw = null;
    }
    }
    catch (System.Exception ex)
    {
    H31Debug.PrintLn("CloseIndex" + ex.Message);
    }

    }

    //建立索引
    public static int AddIndexFromDB()
    {
    int res = 0;
    int count = 0;
    try
    {
    Int32 time0 = System.Environment.TickCount;
    while (count < OneTimeMax && iw != null)
    {
    Int32 time11 = System.Environment.TickCount;
    DataSet ds = H31SQL.GetHashListFromDB(type, startnum, startnum + ONEPAGENUM - 1, NewOrUpdate);
    Int32 time12 = System.Environment.TickCount;
    int cnt = ds.Tables[0].Rows.Count;
    if (ds != null&& cnt>0)
    {
    Int32 time1 = System.Environment.TickCount;
    count = count + cnt;
    for (int i = 0; i < cnt; i++)
    {
    //ID,hashKey,recvTime,updateTime,keyContent,keyType,recvTimes,fileCnt,filetotalSize,Detail,viewTimes,viewLevel
    Document doc = new Document();
    doc.Add(new Field("ID", ds.Tables[0].Rows[i]["ID"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
    doc.Add(new Field("hashKey", ds.Tables[0].Rows[i]["hashKey"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
    doc.Add(new Field("recvTime", ds.Tables[0].Rows[i]["recvTime"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("updateTime", ds.Tables[0].Rows[i]["updateTime"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
    doc.Add(new Field("keyContent", ds.Tables[0].Rows[i]["keyContent"].ToString(), Field.Store.YES, Field.Index.ANALYZED));//存储,索引
    //PanGuFenCiTest(ds.Tables[0].Rows[i]["keyContent"].ToString());
    string typeid=ds.Tables[0].Rows[i]["keyType"].ToString();
    if(typeid.Length<2)
    typeid=type.ToString();
    doc.Add(new Field("keyType", typeid, Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("recvTimes", ds.Tables[0].Rows[i]["recvTimes"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
    doc.Add(new Field("fileCnt", ds.Tables[0].Rows[i]["fileCnt"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("filetotalSize", ds.Tables[0].Rows[i]["filetotalSize"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("Detail", ds.Tables[0].Rows[i]["Detail"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("viewTimes", ds.Tables[0].Rows[i]["viewTimes"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    doc.Add(new Field("viewLevel", ds.Tables[0].Rows[i]["viewLevel"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
    iw.AddDocument(doc);
    }
    ds = null;
    Thread.Sleep(10);
    }
    else
    {
    res = 1;
    break;
    }
    }

    Int32 time10 = System.Environment.TickCount;
    H31Debug.PrintLn("AddIndexFromDB[" + type.ToString() + "],Building index done:" + startnum.ToString() + " Time:" + (time10 - time0).ToString() + "ms");

    }
    catch (System.Exception ex)
    {
    H31Debug.PrintLn(ex.StackTrace);
    }

    return res;
    }

    创建索引代码

    复制代码
        public static class H31Index
        {
            private static Analyzer analyzer = new PanGuAnalyzer(); //MMSegAnalyzer //StandardAnalyzer
            private static int ONEPAGENUM = 200;
            private static string m_indexPath = "";
            private static IndexWriter iw = null;
            public static void Init(string indexpath)
            {
                m_indexPath = indexpath;
            }
    
            public static bool OpenIndex()
            {
                try
                {
    
                    DirectoryInfo INDEX_DIR = new DirectoryInfo(m_indexPath+"//Index");
                    bool iscreate = true;
                    if (INDEX_DIR.Exists)
                        iscreate = false;
                    Int32 time21 = System.Environment.TickCount;
                    if (iw == null)
                    {
                        iw = new IndexWriter(FSDirectory.Open(INDEX_DIR), analyzer, iscreate, new IndexWriter.MaxFieldLength(32));
                        Int32 time22 = System.Environment.TickCount;
                        H31Debug.PrintLn("IndexWriter2[" + type.ToString() + "]:" + " IndexWriter:" + (time22 - time21).ToString() + "ms");
                        return true;
                    }
                }
                catch (System.Exception ex)
                {
                    H31Debug.PrintLn("OpenIndex" + ex.Message);
                }
                return false;
            }
    
            public static void CloseIndex()
            {
                try
                {
                    if (iw != null)
                    {
                        //if (count > 0)
                        {
                            iw.Commit();
                            iw.Optimize();
                        }
                        iw.Dispose();
                        iw = null;
                    }            
                }
                catch (System.Exception ex)
                {
                    H31Debug.PrintLn("CloseIndex" + ex.Message);
                }
    
            }
    
            //建立索引        
    public static int AddIndexFromDB()
            {
                int res = 0;
                int count = 0;
                try
                {
                    Int32 time0 = System.Environment.TickCount;
                    while (count < OneTimeMax && iw != null)
                    {
                        Int32 time11 = System.Environment.TickCount;
                        DataSet ds = H31SQL.GetHashListFromDB(type, startnum, startnum + ONEPAGENUM - 1, NewOrUpdate);
                        Int32 time12 = System.Environment.TickCount;
                        int cnt = ds.Tables[0].Rows.Count;
                        if (ds != null&& cnt>0)
                        {
                            Int32 time1 = System.Environment.TickCount;
                            count = count + cnt;
                            for (int i = 0; i < cnt; i++)
                            {
                                //ID,hashKey,recvTime,updateTime,keyContent,keyType,recvTimes,fileCnt,filetotalSize,Detail,viewTimes,viewLevel
                                Document doc = new Document();
                                doc.Add(new Field("ID", ds.Tables[0].Rows[i]["ID"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
                                doc.Add(new Field("hashKey", ds.Tables[0].Rows[i]["hashKey"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
                                doc.Add(new Field("recvTime", ds.Tables[0].Rows[i]["recvTime"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("updateTime", ds.Tables[0].Rows[i]["updateTime"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
                                doc.Add(new Field("keyContent", ds.Tables[0].Rows[i]["keyContent"].ToString(), Field.Store.YES, Field.Index.ANALYZED));//存储,索引
                                //PanGuFenCiTest(ds.Tables[0].Rows[i]["keyContent"].ToString());
                                string typeid=ds.Tables[0].Rows[i]["keyType"].ToString();
                                if(typeid.Length<2)
                                    typeid=type.ToString();
                                doc.Add(new Field("keyType", typeid, Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("recvTimes", ds.Tables[0].Rows[i]["recvTimes"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,索引
                                doc.Add(new Field("fileCnt", ds.Tables[0].Rows[i]["fileCnt"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("filetotalSize", ds.Tables[0].Rows[i]["filetotalSize"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("Detail", ds.Tables[0].Rows[i]["Detail"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("viewTimes", ds.Tables[0].Rows[i]["viewTimes"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                doc.Add(new Field("viewLevel", ds.Tables[0].Rows[i]["viewLevel"].ToString(), Field.Store.YES, Field.Index.NO));//存储,不索引
                                iw.AddDocument(doc);
                            }
                            ds = null;
                            Thread.Sleep(10);
                        }
                        else
                        {
                            res = 1;
                            break;
                        }
                    }
    
                    Int32 time10 = System.Environment.TickCount;
                    H31Debug.PrintLn("AddIndexFromDB[" + type.ToString() + "],Building index done:" + startnum.ToString() + " Time:" + (time10 - time0).ToString() + "ms");
    
                }
                catch (System.Exception ex)
                {
                    H31Debug.PrintLn(ex.StackTrace);
                }
    
                return res; 
            }
    复制代码

      

    查询代码

    复制代码
            //网站搜索代码
            public static void Search(string keyword,int typeid,int pageNo)
            {
                int onePage=20;//一页多少
                int TotalNum=1000;//一次加载多少
    
                if (pageNo < 0) pageNo = 0;
                if (pageNo * onePage > TotalNum)
                    pageNo = TotalNum / onePage;
    
                //索引加载的目录
                DirectoryInfo INDEX_DIR = new DirectoryInfo(m_indexPath+"//Index//index1");
                IndexSearcher searcher = new IndexSearcher(FSDirectory.Open(INDEX_DIR), true);
                QueryParser qp = new QueryParser(Version.LUCENE_30, "keyContent", analyzer);
                Query query = qp.Parse(keyword); 
                //Console.WriteLine("query> {0}", query);
    
                //设置排序问题
                Sort sort = new Sort(new SortField[]{new SortField("recvTimes", SortField.INT, true),new SortField("updateTime", SortField.STRING, true)});
    
                //设置高亮显示的问题
                PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color="red">", "</font>");
                PanGu.HighLight.Highlighter highlighter =new PanGu.HighLight.Highlighter(simpleHTMLFormatter,new Segment());
                highlighter.FragmentSize = 50;
    
                TopFieldDocs tds = searcher.Search(query,null, 1000, sort);
                Console.WriteLine("TotalHits: " + tds.TotalHits);
    
                /* 计算显示的条目 */
                int count = tds.ScoreDocs.Length;
                int start = (pageNo - 1) * onePage;
                int end = pageNo * onePage > count ? count : pageNo * onePage;
                //返回集合列表
                for (int i = start; i < end; i++)
                {
                    Document doc = searcher.Doc(tds.ScoreDocs[i].Doc);
                    string contentResult = highlighter.GetBestFragment(keyword, doc.Get("keyContent").ToString());
                    Console.WriteLine(contentResult + ">>" + doc.Get("recvTimes") + "<<" + doc.Get("updateTime"));
                }
    
                searcher.Dispose();
            }
    复制代码

     服务器部署的问题                                          

     当你觉得本地都运行的好好的时候,发现到服务器上根本就运行不了,一直报错.

    由于Lucene.net最新版本直接使用了net4.0,服务器是64们的WIN2003,而且运行的网站都还是32位的net2.0的DLL,所以升级到4.0怎么也出不来

    1.运行显示的错误是提示没有.net4.0的框架,需要注册.net4.0

    直接到网上找如何搞定显示ASP.NET选项卡的问题,最后找到文章方法是:

    停止iis直接删除C:/WINDOWS/system32/inetsrv/MetaBase.xml中的Enable32BitAppOnWin64="TRUE" 行

    重启IIS后选项卡到是出来了,但net.2.0的网站全部挂掉,运行不起来,http://h31bt.com网站也运行不起来,

    Enable32BitAppOnWin64的意思是允许运行32们的程序,所以此方法不行.

    2.另外找的文章都是重新注册net 4.0   

    C:WINDOWSMicrosoft.NETFrameworkv4.0.30319aspnet_regiis.exe -i

    开始执行试了好多次,没有效果,这里也允许了,重新安装了好几次Net4.0.

    3.最后一次在停止IIS后,再次全部注册net2.0,4.0,然后

    cscript %SYSTEMDRIVE%inetpubadminscriptsadsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1
    重启IIS后,出现的错误终于不再是上面的.

    新错误是:

    Server Application Unavailable

    4.通过网上查找资料 

    解决办法: 在IIS中新建一个应用程序池,然后选中你的 基于.net 
    framework4.0的虚拟目录,点“属性”-》在“应用程序池” 中选择刚才新建的的应用程序池,点击“确定”。

     最后服务器网站http://h31bt.com终于运行起来了.

      Lucene.net搜索的效果                                          

    1.经过目前测试,目前服务器4G的内存搜索速度比以前需要5S左右的LIKE强了很多倍,基本上都在1S以内;

    2.由于Lucene索引是基于文件的索引,从而使SQL数据库的使用压力减轻不少,这样给其它程序的整体压力减少不少,网站效果还行.

    3.目前500万的数据重新建立一次索引需要1小时左右,但是网站运行的时候去更新索引速度目前感觉比较慢.比如要更新点击次数和更新时间等时,发现新的问题来了,这块的时间比较长.

    4.目前考虑的方案是几天一次全部重新建立索引一次,平时只是添加数据.

    希望有了解的朋友在此留言指教下lucene.net方面的性能优化问题,大家一起共同学习进步.

    大家看累了,就移步到娱乐区http://h31bt.com 去看看速度如何,休息下...

    希望大家多多推荐哦...大家的推荐才是下一篇介绍的动力...

     
     
    分类: C#数据库
    标签: Lucene.net
  • 相关阅读:
    如何通过命令行窗口查看sqlite数据库文件
    eclipse自动补全的设置
    文本装饰
    注释和特殊符号
    文本装饰
    网页背景
    通过ArcGIS Server admin 查看和删除已注册的 Web Adaptor
    通过 ArcGIS Server Manager 查看已安装的 Web Adaptor
    通过 ArcGIS Server Manager 验证 DataStore
    Windows上安装ArcGIS Enterprise——以 Windows Server 2012 R2上安装 ArcGIS 10.8为例
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3388703.html
Copyright © 2020-2023  润新知