MongoDB+Lucence.net

由于公司项目的要求,要求使用lucene进行搜索,数据源是mongodb,所以这里我先简单介绍一下mongodb。

1mongodb

首先是下载mongodb。http://www.mongodb.org/downloads。下载好之后如下图,

里面最重要的是mongo.exe和mongod.exe.你每次启动的话用命令每次都要输入mongod --dbpath D:/MongoDB/data来启动MongoDB。这样非常不方便,而且关机后就得从新启动,所以我推荐启用一个mongo服务

命令如下D:\MongoDB\bin>mongod --logpath D:\MongoDB\logs\MongoDB.log --logappend --dbpath D:\MongoDB\data --directoryperdb --serviceName MongoDB --install

我来解释一下,D:\MongoDB为我的根目录,--logpath D:\MongoDB\logs\MongoDB.log为设置日志 --logappend --dbpath D:\MongoDB\data为设置数据库数据。安装成功后会提示

Creating service MongoDB.
Service creation successful.
Service can be started from the command line via 'net start "MongoDB"'.

注意:logs文件夹和data文件夹要先新建好;serviceName的N字母要大写.

以上就是安装mongodb的方法,mongodb的一些基本语法就不在这里说了,随便一搜到处是。为什么公司要用mongodb,这就要跟mongodb的特性有关了,数据库大致分为两种,关系型和非关系型(当然从别的方面分还可以分成别的)。最主要区别就是关系型是一一对应的,这是它的优点也是缺点。正是这个原因诞生了NOSQL,NOSQL是not only sql 的简称。nosql里面最火的,就属于memcached,mongodb这两个了。这两个的用处也不相同,这里主要说mongodb。mongodb是介于关系型和非关系型之间的一种,发展到现在已经很成熟了,很容易找到你需要的解决方案。mongodb他也有一个缺点,就是不是可视化的,当然也有mongo的可视化工具,但是一般人不用。下面附上mongohelper

  1   public class MongoDBHelper<T> where T : class
  2     {
  3         string connectionString = string.Empty;
  4         string databaseName = string.Empty;
  5         string collectionName = string.Empty;
  6         static MongoDBHelper<T> mongodb;
  7 
  8         public MongoDBHelper(string connectionString, string databaseName, string collectionName)
  9         {
 10             this.collectionName = collectionName;
 11             this.connectionString = connectionString;
 12             this.databaseName = databaseName;
 13         }
 14         
 15         public MongoDB.Configuration.MongoConfiguration configuration
 16         {
 17             get
 18             {
 19                 var config = new MongoDB.Configuration.MongoConfigurationBuilder();
 20                 config.Mapping(mapping =>
 21                 {
 22                     mapping.DefaultProfile(profile =>
 23                     {
 24                         profile.SubClassesAre(t => t.IsSubclassOf(typeof(T)));
 25                     });
 26 
 27                     mapping.Map<T>();//将类型添加到集合中
 28                     mapping.Map<T>();
 29                 });
 30                 config.ConnectionString(connectionString);
 31                 return config.BuildConfiguration();
 32             }
 33         }
 34 
 35         public void Insert(T t)
 36         {
 37             using (MongoDB.Mongo mongo = new MongoDB.Mongo())
 38             {
 39                 try
 40                 {
 41                     mongo.Connect();
 42 
 43                     var db = mongo.GetDatabase(databaseName);
 44 
 45                     var collection = db.GetCollection<T>(collectionName);
 46 
 47                     collection.Insert(t, true);
 48 
 49                     mongo.Disconnect();
 50                 }
 51                 catch (Exception)
 52                 {
 53                     mongo.Disconnect();
 54                     throw;
 55                 }
 56             }
 57         }
 58 
 59         public void Update(T t,Expression<Func<T,bool>>func)
 60         {
 61             using (MongoDB.Mongo mongo=new MongoDB.Mongo())
 62             {
 63                 try
 64                 {
 65                     mongo.Connect();
 66 
 67                     var db = mongo.GetDatabase(databaseName);
 68 
 69                     var collection = db.GetCollection<T>(collectionName);
 70 
 71                     collection.Update(t, func, true);
 72 
 73                     mongo.Disconnect();
 74                 }
 75                 catch (Exception)
 76                 {
 77                     mongo.Disconnect();
 78                     throw;
 79                 }
 80             }
 81         }
 82 
 83         public List<T> GetList(int pageIndex, int pageSize,int needPageCount, Expression<Func<T, bool>> func, out int pageCount)
 84         {
 85             pageCount = 0;
 86 
 87             using (MongoDB.Mongo mongo=new MongoDB.Mongo())
 88             {
 89                 try
 90                 {
 91                     mongo.Connect();
 92 
 93                     var db = mongo.GetDatabase(databaseName);
 94 
 95                     var collection = db.GetCollection<T>(collectionName);
 96 
 97                     pageCount =Convert.ToInt32(collection.Count()/pageSize);
 98 
 99                     var modelList = collection.Linq().Where(func).Skip(pageSize * (pageIndex - 1)).Take(needPageCount * pageSize).Select(i => i).ToList();
100                     
101 
102                     mongo.Disconnect();
103 
104                     return modelList;
105                 }
106                 catch (Exception)
107                 {
108                     mongo.Disconnect();
109                     throw;
110                 }
111             }
112         }
113         public List<T> ListAll(Expression<Func<T, bool>> func)
114         {
115             using (Mongo mongo = new Mongo())
116             {
117                 try
118                 {
119                     mongo.Connect();
120 
121                     var db = mongo.GetDatabase(databaseName);
122 
123                     var collection = db.GetCollection<T>(collectionName);
124 
125                     var list = collection.Linq().Select(i => i).ToList();
126 
127                     mongo.Disconnect();
128 
129                     return list;
130                 }
131                 catch (Exception)
132                 {
133                     mongo.Disconnect();
134                     throw;
135                 }
136             }
137         }
138 
139         public T Single(Expression<Func<T,bool>>func)
140         {
141             using (Mongo mongo=new Mongo())
142             {
143                 try
144                 {
145                     mongo.Connect();
146 
147                     var db = mongo.GetDatabase(databaseName);
148 
149                     var collection = db.GetCollection<T>(collectionName);
150 
151                     var single = collection.Linq().FirstOrDefault(func);
152 
153                     mongo.Disconnect();
154 
155                     return single;
156                 }
157                 catch (Exception)
158                 {
159                     mongo.Disconnect();
160                     throw;
161                 }
162             }
163         }
164 
165         public void Delete(Expression<Func<T,bool>>func)
166         {
167             using (Mongo mongo=new Mongo())
168             {
169                 try
170                 {
171                     mongo.Connect();
172 
173                     var db = mongo.GetDatabase(databaseName);
174                     var collection = db.GetCollection<T>(databaseName);
175                     //这个地方一定要加上T参数,不然会当成object类型的来处理,导致删除失败。
176                     collection.Remove<T>(func);
177                     mongo.Disconnect();
178                 }
179                 catch (Exception)
180                 {
181                     mongo.Disconnect();
182                     throw;
183                 }
184             }
185         }
View Code

2,lucene.net.

lucence.net是lucene的.net移植版本,lucene所解决的问题是站内搜索。通俗的说lucene是把数据库里的数据进行读取,然后根据自己的分词器进行分词,之后你所搜索的关键词都会通过lucene所创建的词库(这个词是加了索引的,所以搜索很快)进行搜索。

还要说明的一点就是lucene自带的分词器不好用,因为这个分词器主要是针对英文进行分词,中文的话,最好用盘古分词。一般都是lucene+pangu这么进行配置。当然现在hubble已经逐渐进行取代lucene了,因为盘古分词和hubb是一个开发团队开发的,用起来好用,速度也有所提升,在之后我会单独写一篇hubble的介绍。lucene的使用者还是很多的。下面代码就是对lucene的读和写(写就是写索引)我看到过一篇lucene对索引写的具体算法http://keben1983.blog.163.com/blog/static/143638081201092854659524/。有兴趣的朋友可以看看。

 1  public class LuceneTest
 2     {
 3 
 4         public void Write(string indexPath,string txt)
 5         {
 6 
 7 
 8             FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());//FS→FileSystem
 9             bool isUpdate = IndexReader.IndexExists(directory);//索引库文件夹存在并且存在索引库特征文件
10             if (isUpdate)
11             {
12                 //同时只能有一段代码对索引库进行写操作!当使用IndexWriter打开directory的时候会自动给索引库上锁。!!!
13                 //如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
14                 if (IndexWriter.IsLocked(directory))
15                 {
16                     IndexWriter.Unlock(directory);//lock:锁。Un—否定。解锁。Do、Undo。
17                 }
18             }
19             IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
20             //for (int i = 1000; i < 1100; i++)
21             //{
22            
23                 Document document = new Document();//一篇文档
24                 //字段的值是字符串类型
25 
26                 //Field.Store表示是否保存字段原值。Field.Store.YE的字段才能用document.Get取出来值
27                 //document.Add(new Field("number", i.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
28                 //要进行全文检索的字段要设置 Field.Index. ANALYZED
29                 document.Add(new Field("body", txt, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
30                 writer.AddDocument(document);//文档写入索引库
31             //}
32             writer.Close();
33             directory.Close();//不要忘了Close,否则索引结果搜不到
34         }
35 
36         /// <summary>
37         /// 
38         /// </summary>
39         /// <param name="indexPath">索引库的位置</param>
40         /// <param name="keyWords">关键字</param>
41         /// <param name="and_or">关键带空格的关键字之间是什么关系如果是and连接就是true,如果是or连接就是false</param>
42         /// <param name="properties">就是文本的写入各个属性</param>
43         public List<string> Read(string indexPath,string keyWords,bool and_or,int startIndex,int showCount,params string[] properties)
44         {
45             FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
46             IndexReader reader = IndexReader.Open(directory, true);
47             IndexSearcher searcher = new IndexSearcher(reader);//Index:索引
48 
49             //搜索条件
50             PhraseQuery query = new PhraseQuery();
51             //foreach (string word in kw.Split(' '))//先用空格,让用户去分词,空格分隔的就是词“计算机   专业”
52             //{
53             //    query.Add(new Term("body", word));
54             //}
55             //query.Add(new Term("body", "简历"));
56            
57             query.Add(new Term("body",keyWords));//Add的查询条件是and的关系
58             //where Contains("body","简历") and Contains("body","大学生")
59              //query.Add(new Term("body",kw));//body中含有kw的文章
60             //query.SetSlop(100);//多个查询条件的词之间的最大距离。在文章中相隔太远一般也就无意义
61             //TopScoreDocCollector是盛放查询结果的容器
62             TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
63             searcher.Search(query, null, collector);//根据query查询条件进行查询,查询结果放入collector容器
64             ScoreDoc[] docs = collector.TopDocs(startIndex, showCount).scoreDocs;//得到所有查询结果中的文档。TopDocs可以实现分页
65 
66             //return searcher.Doc(docs[0].doc).Get("body");
67             List<string> list = new List<string>();
68             for (int i = 0; i < docs.Length; i++)
69             {
70                 ////SqlDataReader是把查询结果放到数据库服务器。DataSet是放入本程序的内容。
71                 ////搜索ScoreDoc[]只能获得文档的id,这样不会把查询结果的Document一次性加载到内存中。降低了内存压力
72                 ////需要获得文档的详细内容的时候通过searcher.Doc来根据文档id来获得文档的详细内容对象Document
73                 int docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id)
74                 Document doc = searcher.Doc(docId);//找到文档id对应的文档详细信息
75                 //textBox1.AppendText(doc.Get("number") + "\n");//取出放进去字段的值
76                 //textBox1.AppendText(doc.Get("body") + "\n");//Field.Store.YE的字段才能用document.Get取出来值
77                 //textBox1.AppendText("-----------------------\n");
78                list.Add(doc.Get("body"));
79             }
80             return list;
81           
82   
83         }
84     }
lucene

当然这只是针对数据库里单个字段进行匹配,要想针对多个字段,就多加几个document.Add()。但是这样的话,读的时候就不能只从一个字段读,例如:标题或正文包括lucene,并且时间在20060101到20060130之间的文章;

 1                 Directory dir = FSDirectory.getDirectory(PATH, false);   
 2                 IndexSearcher is = new IndexSearcher(dir);   
 3                 QueryParser parser = new QueryParser("content", new StandardAnalyzer());   
 4                 Query query = parser.parse("+(title:lucene content:lucene) +time:[20060101 TO 20060130]";   
 5                 Hits hits = is.search(query);   
 6                 for (int i = 0; i < hits.length(); i++)   
 7                 {   
 8                 Document doc = hits.doc(i);   
 9                 System.out.println(doc.get("title");   
10                 }   
11                 is.close();  
View Code

这样就能多条件,多字段搜索了。
第一次写博文,写的不好,见谅。等过两天写hubble+sql和hubble+mongodb

原文地址:https://www.cnblogs.com/sixiangqimeng/p/3080077.html