菜鸟第一次体验 Lucene.net 之杂谈

时间:2022-02-20 16:23:48
 谈之前先听我啰嗦两句~亲。我秉承了自己一贯作风~拿来主义。当领导对我说:下个项目WEB前端用索引Lucene.Net+盘古分词和XML,完全脱离数据库。听到这些两眼一抹黑,咋办压根连听都很少听到过啊!万念俱灰的感觉,为了金钱只能咬牙切齿蹦出来两个字:拼了。毕竟在我很遥远时代听过,看过感觉太复杂永远也用不到丢弃了。没想到这次“美梦”成真了。只能依靠万能的 百度 CSDN 博客园,拼命找啊。找了好多,不是版本太低,就是我水平不够,理解不透,好吧菜鸟只是水平下等,大虾们原谅。通过种种把终于开始第一个DEMO,没办法只能,时间就是金钱~我的朋友(摘WOW)。
  就从我亲身体验开始啊,希望大家一起探讨,不带人身攻击的提前声明:可以拍砖~探讨~我是带着学习的心态来和大虾们学习的!
 不罗嗦了,先开始第一部分 :创建索引和增删改索引
  Lucene.Net 版本用的2.9。。。。。。PanGu盘古用的2.3,
下载地址: http://download.csdn.net/detail/u012076966/6245759
 下载后 怎么引用就不说了,如果不会~自宫算了 o(∩_∩)o 哈哈

 
 使用盘古分词钱别忘记~加载盘古引用路径:

           //定义盘古分词的xml引用路径
            PanGu.Segment.Init(PanGuXmlPath);

/*  ------------------==============创建索引开始=============---------------    */
        /// <summary>
        /// 创建索引生成
        /// </summary>
        private void CreateIndex()
        {
            IndexWriter writer = null;
            try
            {
                //创建索引目录
                if (!Directory.Exists(IndexDic))//配置文件放最后亲
                {
                    Directory.CreateDirectory(IndexDic);
                }
                /* 注释掉的是数据库抓取的数据循环的,带着学习心态的  同志们,请自行读取,这里辛苦你们了*/
                //从数据库获取数据
               // DataTable dt = NULL;
                //IndexWriter第三个参数:true指重新创建索引,false指从当前索引追加....此处为新建索引所以为---true。这里用的盘古分词
                writer = new IndexWriter(IndexDic, PanGuAnalyzer, true, Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);

                //if (dt.Rows.Count > 0)
                //{
                //    for (int i = 0; i < dt.Rows.Count; i++)
                //    {

                        #region 数据库读取数据 赋值给自定义值
                        string No = "NO12345";
                        string Name = "数据库读取的亲们";
                        string Price = "0.00";
                        //if (!string.IsNullOrEmpty(Price))
                        //{
                        //    Price = "1.11";
                        //}
                        #endregion
                        #region 赋值 并生成索引
                        Document doc = new Document();
//只做存储~不分词
                        doc.Add(new Field("No", No, Field.Store.YES, Field.Index.NOT_ANALYZED));
//名字进行分词
                        doc.Add(new Field("Name", Name, Field.Store.YES, Field.Index.ANALYZED));
                       
                        //方便排序,根据价格区间排序 前需要把参数具体化,我百度出的自我感觉最好办法,如有更好请告知 谢谢
                        Fieldable PriceValue = new NumericField("Price", Field.Store.YES, true);
                        ((NumericField)PriceValue).SetFloatValue(float.Parse(Price));
                        doc.Add(PriceValue);
                      
                        #endregion
                        //执行添加索引
                        writer.AddDocument(doc);
                //    }
                //}

                //索引重排
                writer.Optimize();
                writer.Close();

            }
            catch 
            {
               //出错也不要忘记关闭
                writer.Close(); 
            }
        }

 /// <summary>
        /// 引存放目录
        /// </summary>
        protected string IndexDic
        {
            get
            {
                return Server.MapPath("/NewIndexDic/Seach");
            }
        }

 /// <summary>
        /// 盘古分词器
        /// </summary>
        protected Analyzer PanGuAnalyzer
        {
            get { return new PanGuAnalyzer(); }
        }

        /// <summary>
        /// 盘古分词的配置文件
        /// </summary>
        protected string PanGuXmlPath
        {
            get
            {
                return Server.MapPath("/PanGu/PanGu.xml");
            }
        }

修改删除增加,明天继续 ~洗澡

24 个解决方案

#1


有错别字,见谅,语文不及格

#2


第一次分享 发帖 可能有些混乱~ 菜鸟第一次体验 Lucene.net 之杂谈

#3


感谢你的分享啊。

如果没有人回复,你是可以自己编辑的。

#4


多谢分享呀,虽然还没用过,不过,看了挺有触发的

#5


引用 3 楼 caozhy 的回复:
感谢你的分享啊。

如果没有人回复,你是可以自己编辑的。

3Q

#6


整理下思路,开始增删改,其实也不复杂,只是说下 搜索出来的资料整理下而已,

#7


增加、修改、删除 和创建基本一样,需要注意的是:
//第三个参数要为:false,我注释里面也有些,如果仔细看
  writer = new IndexWriter(IndexDic, PanGuAnalyzer, false, Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);
/* 第二个注意是调用函数不一样我分别写出来 */
 //添加一条新的索引
     writer.AddDocument(doc);
 //修改一条索引
     Term term = new Term("No", No);
     writer.UpdateDocument(term, doc);
 //删除一条索引
     Term term = new Term("No", No);
      writer.DeleteDocuments(term);

看了是不是挺简单,接下来就是 查询了

#8


生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

#9


当时大概几个G的HTML静态文件(具体多少G记不清了),生成索引以后大概在700M左右。

#10


引用 8 楼 5653325 的回复:
生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

是啊,不过自带分词我感觉最好用的就是:SimpleAnalyzer()可以按标点符号分词,这样对我前端属性搜索非常便利,盘古分词真心不行,不知道大侠们有办法没(比如:无线上网,停车位,外送),盘古分词可以按标点符号分词最好了

#11


忘记增加了一个索引字段:
//当WEB前端搜索显示全部索引库数据时候,我网上找资料好像没有很的好解决方案,都是在做索引的时候增加一个特殊字段索引或其他,我就是利用增加一个特殊字段索引,当用户搜索显示全部数据时候,传入参数:alllist 就能查询出所有索引库数据,如果有更好办法请告知下,这里先谢了。
 doc.Add(new Field("AllList", "alllist", Field.Store.YES, Field.Index.NOT_ANALYZED));

#12


引用 10 楼 u012076966 的回复:
Quote: 引用 8 楼 5653325 的回复:

生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

是啊,不过自带分词我感觉最好用的就是:SimpleAnalyzer()可以按标点符号分词,这样对我前端属性搜索非常便利,盘古分词真心不行,不知道大侠们有办法没(比如:无线上网,停车位,外送),盘古分词可以按标点符号分词最好了

我当时那个是针对静态HTML文件做的全文检索。
当时有HTML、分词库、索引库、索引建立更新程序(winform)、搜索功能(webform)组成,基本没涉及到数据库。

流程是先用winform读取分词库来给所有的html建立索引库,然后搜索的时候根据用户传递过来的关键字返回符合关键字的html的url路径。

所以这个分词库需要每周更新(没法做到那么智能,会自动区分关键字),每周更新索引。更新索引的时间比较长(4-6G大概需要4个小时左右(单线程))。

我这方法是最笨的方法,当时也是百度不到文档,自己扣出来的。最终总算是实现了。

不过现在像百度和google都带的有站内搜索,用着还是比较方便的。引用一个js就行了。

#13


分享一些简单lucene.net属性说明整理了下,很简单,凭着分享精神 不收积分,哈哈。顺带附上了盘古分词的维护工具
http://download.csdn.net/detail/u012076966/6247193

#14


感谢分享

#15


菜鸟第一次体验 Lucene.net 之杂谈 慢慢来,整理下工作,交接辞职 菜鸟第一次体验 Lucene.net 之杂谈

#16


菜鸟一枚路过,收藏了,以后“美梦”成真时说不定用得上! 菜鸟第一次体验 Lucene.net 之杂谈

#17


引用 16 楼 yw39019724 的回复:
菜鸟一枚路过,收藏了,以后“美梦”成真时说不定用得上! 菜鸟第一次体验 Lucene.net 之杂谈
菜鸟第一次体验 Lucene.net 之杂谈

#18


楼主好人啊,这个lucene现在不开源了吧。

#19


测试下,可以回复了不

#20


/* ----------------===============简单搜索============--------------- */ 
/// <summary>
        /// 加载绑定数据
        /// </summary>
        protected void Bind()
        {
   
                string Name = txtName.Text;
        string Alllist="1";//URL传值
                //价格区间查询
                string PriceStart = txtStart.Text;
                string PriceEnd = txtEnd.Text;
                Hits myhit = null;
        //IndexDic 索引配置文件,上面已发
                IndexSearcher mysea = new IndexSearcher(IndexDic);

                //SortField构造函数第三个字段true为降序,false为升序
                string strListDesc = ddlOrder.SelectedValue;//排序字段
                Sort sort = null;
               //排序字段 price
                if (strListDesc == "1")
                {
                    sort = new Sort(new SortField("price", SortField.AUTO, false));
                }
                else
                {
                    sort = new Sort(new SortField("price", SortField.AUTO, true));
                }
     

                BooleanQuery booleanQuery = new BooleanQuery();
                TermQuery termNO = null;
                TermQuery termAllList= null;

                //查询所有
               if(Alllist=="1")
        {

                        termAllList= new TermQuery(new Term("AllList", "alllist"));
                   
                    booleanQuery.Add(termAllList , BooleanClause.Occur.MUST);
              }
               //按盘古分词查询
               if(Name!="")
                {
                    Name  = GetKeyWordsSplitBySpace(Name);
                    QueryParser parse = new QueryParser("Name", PanGuAnalyzer);
                    Query query = parse.Parse(Name);
                    parse.SetDefaultOperator(QueryParser.Operator.OR);
                    booleanQuery.Add(query, BooleanClause.Occur.MUST);
                }
 
                Filter filter = null;
                //价格 区间查询
                if (PriceStart != "" && PriceEnd != "")
                {
                    float fspc = float.Parse(PriceStart);
                    float fepc = float.Parse(PriceEnd );

                    booleanQuery.Add(NumericRangeQuery.NewFloatRange("Price", fspc, fepc, true, true), BooleanClause.Occur.MUST);


                }
            
        
                //分页我使用的是 第三方分页控件
                TopDocs docs = mysea.Search(booleanQuery, filter, AspNetPager1.StartRecordIndex + AspNetPager1.PageSize - 1, sort);
                AspNetPager1.RecordCount = docs.totalHits;
                if (docs != null && docs.totalHits > 0)
                {
                  
                    DataRow myrow;
                    DataTable mytab = new DataTable();
    
                    mytab.Columns.Add("No");
                    mytab.Columns.Add("Name");
                    mytab.Columns.Add("Price1");
                    mytab.Clear();
                    for (int i = 0; i < docs.totalHits; i++)
                    {
                        //分页读取数据
                        if (i >= AspNetPager1.StartRecordIndex - 1 && i < AspNetPager1.StartRecordIndex + AspNetPager1.PageSize - 1)
                        {
                            Document doc = mysea.Doc(docs.scoreDocs[i].doc);
                            myrow = mytab.NewRow();
                            #region 给DataTable每行赋值根据DataRow
                            myrow[0] = doc.Get("No").ToString();
                            myrow[1] = doc.Get("Name").ToString();
                            myrow[2] = doc.Get("Price1").ToString();
                            #endregion
                            mytab.Rows.Add(myrow);
                            myrow.AcceptChanges();


                        }
                    }
                    //绑定数据控件
        rp_Item.DataSource=mytab;
                    rp_Item.DataBind();
                  
                    mysea.Close();
            
                }
        }








 /// <summary>
        /// 处理关键字为索引格式
        /// </summary>
        /// <param name="keywords"></param>
        /// <returns></returns>
        private string GetKeyWordsSplitBySpace(string keywords)
        {
            PanGuTokenizer ktTokenizer = new PanGuTokenizer();
            StringBuilder result = new StringBuilder();
            ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);
            foreach (WordInfo word in words)
            {
                if (word == null)
                {
                    continue;
                }
                result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
            }
            return result.ToString().Trim();
        }

#21


感谢分享,建议写到个人的blog里面 菜鸟第一次体验 Lucene.net 之杂谈

#22


简单把,基本上结束了。有空整理个小DEMO ,其实好多也是我拿别人的,直接用的,这里谢谢那些大虾们

#23


引用 21 楼 nice_fish 的回复:
感谢分享,建议写到个人的blog里面 菜鸟第一次体验 Lucene.net 之杂谈

不错 建议,我去看看嘿嘿

#24


 LZ,你好啊!我用的也是盘古分词,但是搜索有些单个字的时候查出来的数据不完整,您能帮我分析一下吗?
QQ:237377144,  谢谢LZ

#1


有错别字,见谅,语文不及格

#2


第一次分享 发帖 可能有些混乱~ 菜鸟第一次体验 Lucene.net 之杂谈

#3


感谢你的分享啊。

如果没有人回复,你是可以自己编辑的。

#4


多谢分享呀,虽然还没用过,不过,看了挺有触发的

#5


引用 3 楼 caozhy 的回复:
感谢你的分享啊。

如果没有人回复,你是可以自己编辑的。

3Q

#6


整理下思路,开始增删改,其实也不复杂,只是说下 搜索出来的资料整理下而已,

#7


增加、修改、删除 和创建基本一样,需要注意的是:
//第三个参数要为:false,我注释里面也有些,如果仔细看
  writer = new IndexWriter(IndexDic, PanGuAnalyzer, false, Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);
/* 第二个注意是调用函数不一样我分别写出来 */
 //添加一条新的索引
     writer.AddDocument(doc);
 //修改一条索引
     Term term = new Term("No", No);
     writer.UpdateDocument(term, doc);
 //删除一条索引
     Term term = new Term("No", No);
      writer.DeleteDocuments(term);

看了是不是挺简单,接下来就是 查询了

#8


生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

#9


当时大概几个G的HTML静态文件(具体多少G记不清了),生成索引以后大概在700M左右。

#10


引用 8 楼 5653325 的回复:
生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

是啊,不过自带分词我感觉最好用的就是:SimpleAnalyzer()可以按标点符号分词,这样对我前端属性搜索非常便利,盘古分词真心不行,不知道大侠们有办法没(比如:无线上网,停车位,外送),盘古分词可以按标点符号分词最好了

#11


忘记增加了一个索引字段:
//当WEB前端搜索显示全部索引库数据时候,我网上找资料好像没有很的好解决方案,都是在做索引的时候增加一个特殊字段索引或其他,我就是利用增加一个特殊字段索引,当用户搜索显示全部数据时候,传入参数:alllist 就能查询出所有索引库数据,如果有更好办法请告知下,这里先谢了。
 doc.Add(new Field("AllList", "alllist", Field.Store.YES, Field.Index.NOT_ANALYZED));

#12


引用 10 楼 u012076966 的回复:
Quote: 引用 8 楼 5653325 的回复:

生成索引是比较麻烦的。
我原来那个用的是ShootAnalyzer的分词,每周生成一次索引(要不然有的新的关键词原分词系统里面没有的就检索不到)。

是啊,不过自带分词我感觉最好用的就是:SimpleAnalyzer()可以按标点符号分词,这样对我前端属性搜索非常便利,盘古分词真心不行,不知道大侠们有办法没(比如:无线上网,停车位,外送),盘古分词可以按标点符号分词最好了

我当时那个是针对静态HTML文件做的全文检索。
当时有HTML、分词库、索引库、索引建立更新程序(winform)、搜索功能(webform)组成,基本没涉及到数据库。

流程是先用winform读取分词库来给所有的html建立索引库,然后搜索的时候根据用户传递过来的关键字返回符合关键字的html的url路径。

所以这个分词库需要每周更新(没法做到那么智能,会自动区分关键字),每周更新索引。更新索引的时间比较长(4-6G大概需要4个小时左右(单线程))。

我这方法是最笨的方法,当时也是百度不到文档,自己扣出来的。最终总算是实现了。

不过现在像百度和google都带的有站内搜索,用着还是比较方便的。引用一个js就行了。

#13


分享一些简单lucene.net属性说明整理了下,很简单,凭着分享精神 不收积分,哈哈。顺带附上了盘古分词的维护工具
http://download.csdn.net/detail/u012076966/6247193

#14


感谢分享

#15


菜鸟第一次体验 Lucene.net 之杂谈 慢慢来,整理下工作,交接辞职 菜鸟第一次体验 Lucene.net 之杂谈

#16


菜鸟一枚路过,收藏了,以后“美梦”成真时说不定用得上! 菜鸟第一次体验 Lucene.net 之杂谈

#17


引用 16 楼 yw39019724 的回复:
菜鸟一枚路过,收藏了,以后“美梦”成真时说不定用得上! 菜鸟第一次体验 Lucene.net 之杂谈
菜鸟第一次体验 Lucene.net 之杂谈

#18


楼主好人啊,这个lucene现在不开源了吧。

#19


测试下,可以回复了不

#20


/* ----------------===============简单搜索============--------------- */ 
/// <summary>
        /// 加载绑定数据
        /// </summary>
        protected void Bind()
        {
   
                string Name = txtName.Text;
        string Alllist="1";//URL传值
                //价格区间查询
                string PriceStart = txtStart.Text;
                string PriceEnd = txtEnd.Text;
                Hits myhit = null;
        //IndexDic 索引配置文件,上面已发
                IndexSearcher mysea = new IndexSearcher(IndexDic);

                //SortField构造函数第三个字段true为降序,false为升序
                string strListDesc = ddlOrder.SelectedValue;//排序字段
                Sort sort = null;
               //排序字段 price
                if (strListDesc == "1")
                {
                    sort = new Sort(new SortField("price", SortField.AUTO, false));
                }
                else
                {
                    sort = new Sort(new SortField("price", SortField.AUTO, true));
                }
     

                BooleanQuery booleanQuery = new BooleanQuery();
                TermQuery termNO = null;
                TermQuery termAllList= null;

                //查询所有
               if(Alllist=="1")
        {

                        termAllList= new TermQuery(new Term("AllList", "alllist"));
                   
                    booleanQuery.Add(termAllList , BooleanClause.Occur.MUST);
              }
               //按盘古分词查询
               if(Name!="")
                {
                    Name  = GetKeyWordsSplitBySpace(Name);
                    QueryParser parse = new QueryParser("Name", PanGuAnalyzer);
                    Query query = parse.Parse(Name);
                    parse.SetDefaultOperator(QueryParser.Operator.OR);
                    booleanQuery.Add(query, BooleanClause.Occur.MUST);
                }
 
                Filter filter = null;
                //价格 区间查询
                if (PriceStart != "" && PriceEnd != "")
                {
                    float fspc = float.Parse(PriceStart);
                    float fepc = float.Parse(PriceEnd );

                    booleanQuery.Add(NumericRangeQuery.NewFloatRange("Price", fspc, fepc, true, true), BooleanClause.Occur.MUST);


                }
            
        
                //分页我使用的是 第三方分页控件
                TopDocs docs = mysea.Search(booleanQuery, filter, AspNetPager1.StartRecordIndex + AspNetPager1.PageSize - 1, sort);
                AspNetPager1.RecordCount = docs.totalHits;
                if (docs != null && docs.totalHits > 0)
                {
                  
                    DataRow myrow;
                    DataTable mytab = new DataTable();
    
                    mytab.Columns.Add("No");
                    mytab.Columns.Add("Name");
                    mytab.Columns.Add("Price1");
                    mytab.Clear();
                    for (int i = 0; i < docs.totalHits; i++)
                    {
                        //分页读取数据
                        if (i >= AspNetPager1.StartRecordIndex - 1 && i < AspNetPager1.StartRecordIndex + AspNetPager1.PageSize - 1)
                        {
                            Document doc = mysea.Doc(docs.scoreDocs[i].doc);
                            myrow = mytab.NewRow();
                            #region 给DataTable每行赋值根据DataRow
                            myrow[0] = doc.Get("No").ToString();
                            myrow[1] = doc.Get("Name").ToString();
                            myrow[2] = doc.Get("Price1").ToString();
                            #endregion
                            mytab.Rows.Add(myrow);
                            myrow.AcceptChanges();


                        }
                    }
                    //绑定数据控件
        rp_Item.DataSource=mytab;
                    rp_Item.DataBind();
                  
                    mysea.Close();
            
                }
        }








 /// <summary>
        /// 处理关键字为索引格式
        /// </summary>
        /// <param name="keywords"></param>
        /// <returns></returns>
        private string GetKeyWordsSplitBySpace(string keywords)
        {
            PanGuTokenizer ktTokenizer = new PanGuTokenizer();
            StringBuilder result = new StringBuilder();
            ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);
            foreach (WordInfo word in words)
            {
                if (word == null)
                {
                    continue;
                }
                result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
            }
            return result.ToString().Trim();
        }

#21


感谢分享,建议写到个人的blog里面 菜鸟第一次体验 Lucene.net 之杂谈

#22


简单把,基本上结束了。有空整理个小DEMO ,其实好多也是我拿别人的,直接用的,这里谢谢那些大虾们

#23


引用 21 楼 nice_fish 的回复:
感谢分享,建议写到个人的blog里面 菜鸟第一次体验 Lucene.net 之杂谈

不错 建议,我去看看嘿嘿

#24


 LZ,你好啊!我用的也是盘古分词,但是搜索有些单个字的时候查出来的数据不完整,您能帮我分析一下吗?
QQ:237377144,  谢谢LZ