发表于 2015-6-27 17:27:21

Lucene.Net, SQL Server 2008全文检索, Like模糊查询的一点心得

  1.Like 模糊查询
  例如: select * from table where productdes like '%cad%'
  它不能利用索引查询, 只能是全表扫描, 效率较低, 而且不会分词, 只能按关键字老老实实的查, 但查询实时数据, 结果准确.
  
  2.SQL Server 2008全文检索
  为了提高效率, 换用sql server的全文检索, 怎么建全文检索就此略去, 不提, 只看查询方法.
  例如: select * from table where contains(ProductDesc, '*cad*')
  它查询的效率很高, 支持中文分词(但好不好就另说了), 但缺点竟然是在英文查询上, 如果想模糊查询带cad三个字母的数据, 它只能搜索出以cad为完整单词的数据, 例如: 它能查出abc cad , cad def, 或者cad, 它不能查出autocad这种字母连在一起的数据, 也就是说, sql server的全文检索的英文分词是空格, 要想查连在一起的英文词, 它办不到, 得另寻第三方的全文索引了, ms如果在这里开个可扩展的口子多好, 可惜了.
  索引的更新填充问题: 创建好全文检索就自动来一次完全填充, 如果在跟踪更改处选择自动, 全文检索就会采用基于更改跟踪的填充, 原表数据一旦有改动, 就会从后台悄悄地传播过来, 自动的更新全文索引. 具体可参考http://msdn.microsoft.com/zh-cn/library/ms142575.aspx
  在更新全文索引之前这段时间, 搜不到新录入但未收入全文索引的数据, 但like可查到. 虽然不是实时的, 但是经过测试, 我发现这个更新速度非常之快, 几乎一改原表, 全文索引就更新了, 所以我觉得可以认为实时的, 估计sqlserver内部应该是用观察者模式实现这个功能的.
  另外, contains包含的列都必须来自同一个表, 不能跨表, 例如where contains(a.ProductDesc, b.ProductName, '*cad*'), 这样是不行的.
  
  3.Lucene全文检索
  SQL server全文检索不灵了, 只能找第三方的方案了, 首当其冲的就是Lucene了, 但在.net下, Lucene却很不顺当.
  NLucene是将 Lucene 从 Java 移植到 .NET 的一个 SourceForge 项目,它从 Lucene 1.2 版本转化而来, 但2002年就停止更新了.
  因为 NLucene 项目到2002年就没有再推出新的版本,可Lucene 却一直在发展,于是有人把Lucene 1.3版移植到.NET就成了Lucene .NET,但是Lucene .Net发展到2.0版的时候变成了商业化的产品,脱离了开源项目, 听说现在进了孵化器已停止开发了, 但上官网http://incubator.apache.org/lucene.net/download.html上看, 还仍然在更新中似乎没有停止, 最新开源的版本是2.9.2, 发布日期是2011年5月6日, 他们还在准备2.9.4版.
  受到Lucene.Net脱离开源项目的影响,有人为了继续发展开源.Net搜索引擎,于是在Lucene.Net的原有基础上继续发展该项目,但是名字改成了DotLucene以区别于Lucene.Net。但现在打开官网一看, 得, 又停止了. 看来, 只能用Lucene.Net2.0这最后一个开源版本了.
  索引的更新填充问题: 也是要隔一段时间更新一次索引, 也是不可实时更新的, 需要定期更新填充才可以, 如果需要频繁更新推荐删除旧的然后重建索引.
  
  建索引, 查索引的代码如下:
  private void btnCreateIndex_Click(object sender, EventArgs e)
      {
            StringBuilder sbSQL = new StringBuilder();
            sbSQL.AppendLine(" Select ProductName, ProductDesc from Tbl_Product");
            dt = DataHelper.RetrieveData(sbSQL.ToString());
            
            //建立索引
            IndexWriter writer = CreateIndex(dt);
      }
  public IndexWriter CreateIndex(DataTable dt)
      {
            IndexWriter writer = new IndexWriter("c:/index/", new StandardAnalyzer(), true);
            try
            {
                //建立索引字段
                foreach(DataRow dr in dt.Rows)
                {
                  Document doc=new Document();
                  doc.Add(new Field("ProductName", dr.ToString(), Field.Store.YES, Field.Index.TOKENIZED));
                  doc.Add(new Field("ProductDesc", dr.ToString(), Field.Store.YES, Field.Index.TOKENIZED));
                  writer.AddDocument(doc);                                    
                }
                writer.Optimize();
                writer.Close();
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);               
            }
            return writer;
      }
  private void Search_Click(object sender, EventArgs e)
      {
            string key = this.textBox1.Text;
  IndexSearcher search = new IndexSearcher(@"c:/index/"); //把刚才建立的索引取出来
  Term t = new Term("ProductDesc", "*" + key + "*");
            WildcardQuery query = new WildcardQuery(t);
  Hits hit = search.Search(query);
  DataTable dt = new DataTable();
            dt.Columns.Add("ProductDesc");
  for (int i = 0; i
页: [1]
查看完整版本: Lucene.Net, SQL Server 2008全文检索, Like模糊查询的一点心得