本节我给大家测试一下Linux环境的Solr,通过增删改查的实例demo看看Solr环境是否已经OK。记得有哥们留言,问到只看见Solr和Cassandra的单独环境搭建,却不见它们的协同。我想说这两个没有什么必然的联系,在Cassandra的DSE版本,在Cassandra的内部继承了一套Solr的环境,只需要开启开关,就可以自动往Solr同步数据。但是这个嵌入的版本性能太差,无法使用。那么它们之间要怎么样联系呢?因为cassandra的二级索引查询速度不尽如人意,而且查询的语法有限,所以我们引入Solr,用Solr查询出主键,再去Cassandra根据主键查询出想要的速度,总结来说就是Solr中存储一些用于查询的字段,而Cassandra中存储所有要用到的数据,Solr负责查询,Cassandra集群负责数据。
这两天在使用Solr的时候碰到一个问题,由于我的Schema定义如下
当时我少定义了一个uniqueKey,结果报错,但是我加上后重启Tomcat,还是报这个错误,后来一直没解决掉。第二天,我发现居然自己好了,于是看了一下Tomcat的bin目录,没有shutdown.sh,只有startup.sh。我想着是不是因为没有shutdown的原因,我就采用kill进程的方式,关闭了一下tomcat,然后重启,发现就是因为没有关闭tomcat的原因。
[root@bogon ~]# ps -ef |grep tomcat root 5079 1 3 23:02 ? 00:00:20 /usr/java/jdk1.7.0_21/bin/java -Djava.util.logging.config.file=/usr/apache-tomcat-7.0.40/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/apache-tomcat-7.0.40/endorsed -classpath /usr/apache-tomcat-7.0.40/bin/bootstrap.jar:/usr/apache-tomcat-7.0.40/bin/tomcat-juli.jar -Dcatalina.base=/usr/apache-tomcat-7.0.40 -Dcatalina.home=/usr/apache-tomcat-7.0.40 -Djava.io.tmpdir=/usr/apache-tomcat-7.0.40/temp org.apache.catalina.startup.Bootstrap start root 6128 6093 0 23:12 pts/0 00:00:00 grep tomcat [root@bogon ~]# kill -9 5079 [root@bogon ~]# cd /usr [root@bogon usr]# cd apache-tomcat-7.0.40 [root@bogon apache-tomcat-7.0.40]# cd bin [root@bogon bin]# sh startup.sh Using CATALINA_BASE: /usr/apache-tomcat-7.0.40 Using CATALINA_HOME: /usr/apache-tomcat-7.0.40 Using CATALINA_TMPDIR: /usr/apache-tomcat-7.0.40/temp Using JRE_HOME: /usr/java/jdk1.7.0_21 Using CLASSPATH: /usr/apache-tomcat-7.0.40/bin/bootstrap.jar:/usr/apache-tomcat-7.0.40/bin/tomcat-juli.jar
OK,既然没有问题,我们进入正题,修改Sol实例目录下的SolrConfig.xml文件中的内容
<cores adminPath="/admin/cores" defaultCoreName="MyTest.UserInfo" host="${host:}" hostPort="${jetty.port:8080}" hostContext="${hostContext:solr}" zkClientTimeout="${zkClientTimeout:15000}"> <core name="MyTest.UserInfo" instanceDir="Test" /> </cores>
Core Name设置为MyTest.UserInfo。
OK,重新启动Solr,我们打开浏览器,如下
我们实例名称已经成为刚才设置的名称(MyTest.UserInfo)。
接下来我们要看的是我们的程序
Entity下面是我们定义的Solr实体,如下
namespace SolrCURDDemo { using SolrNet; using SolrNet.Attributes; public class UserInfoEntity { public UserInfoEntity() { } [SolrUniqueKey("UserNO")] public string UserNO { get; set; } [SolrField("Name")] public string Name { get; set; } [SolrField("Age")] public int? Age { get; set; } [SolrField("IsMarried")] public bool? IsMarried { get; set; } } }
和我们刚才定义的Solr Schema一致。然后Reference下面是我们要引用的dll,SolrNet.dll和Microsoft.Practises.ServiceLocation.dl。我下载的SolrNet是0.4.0.2002,大家在网上自己去下。
接下来是我们的SolrConfig配置文件,这个是我自定义的一个xml文件
<?xml version="1.0" encoding="utf-8" ?> <SolrConfigCollection> <SolrConfigs baseAddress="Http://192.168.192.128:8080/MyTest."> <Schema name="UserInfo" entityName="SolrCURDDemo.UserInfoEntity"></Schema> </SolrConfigs> <!--<SolrConfigs baseAddress="Http://192.168.192.128:8080/MyOtherTest."> <Schema name="UserInfo"></Schema> </SolrConfigs>--> </SolrConfigCollection>
什么意思呢?在这里我的意思是 一个地址可以有多个Schema,或者多个地址,假如我有这样的一个需求,一个Solr服务负责学生的基信息,一个Solr服务负责学生的成绩信息,那么我们就配置两个SolrConfigs。
接下来是我们Utility,主要是SolrHelper和SolrCollection类
namespace SolrCURDDemo { using SolrNet; using Microsoft.Practices.ServiceLocation; using System.Reflection; using SolrNet.Commands.Parameters; using System.Configuration; public class SolrHelper { private static bool isRegister; private static SolrHelper solrHelper = new SolrHelper(); private SolrHelper() { } private static int MaxQueryCount { get { return int.Parse(ConfigurationManager.AppSettings["MaxQueryCount"].ToString()); } } public static SolrHelper GetInstance() { if (!isRegister) { RegisterSolrInstance(); isRegister = true; } return solrHelper; } private static void RegisterSolrInstance() { string path = AppDomain.CurrentDomain.BaseDirectory + @"\SolrConfig\SolrConfig.xml"; SolrCollection solrCollection = Deserialize<SolrCollection>(path); Type startUpType = typeof(Startup); foreach (SolrConfigs solrConfig in solrCollection.SolrConfigs) { foreach (SchemaInfo schema in solrConfig.Schemas) { MethodInfo method = startUpType.GetMethod("Init", new Type[] { typeof(string) }) .MakeGenericMethod(Type.GetType(schema.EntityType)); method.Invoke(null, new object[] { solrConfig.BaseAddress + schema.ServiceName }); } } } private static T Deserialize<T>(string path) where T : class,new() { XmlReader xmlReader = XmlReader.Create(path); XmlSerializer xmlSer = new XmlSerializer(typeof(SolrCollection)); object deSerializeObj = xmlSer.Deserialize(xmlReader); xmlReader.Close(); return deSerializeObj as T; } private ISolrOperations<T> GetSolrOperation<T>() { return ServiceLocator.Current.GetInstance<ISolrOperations<T>>(); } #region solr operations #region query public List<T> QueryByFilter<T>(string filter) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); SolrQueryResults<T> result = solrOperation.Query(filter); return result.ToList(); } catch (Exception ex) { throw ex; } } public List<T> QueryByFilter<T>(ISolrQuery solrQuery) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); SolrQueryResults<T> result = solrOperation.Query(solrQuery); return result.ToList(); } catch (Exception ex) { throw ex; } } public List<T> QueryByFilter<T>(string filter, Dictionary<string, string> sortDictionary) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); List<SortOrder> sortOrderList = new List<SortOrder>(); foreach (KeyValuePair<string, string> sortPair in sortDictionary) { SortOrder sortOrder = new SortOrder(sortPair.Key, (Order)Enum.Parse(typeof(Order), sortPair.Value)); sortOrderList.Add(sortOrder); } SolrQueryResults<T> result = solrOperation.Query(filter, sortOrderList); return result.ToList(); } catch (Exception ex) { throw ex; } } public List<T> QueryByFilter<T>(ISolrQuery solrQuery, Dictionary<string, string> sortDictionary) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); List<SortOrder> sortOrderList = new List<SortOrder>(); foreach (KeyValuePair<string, string> sortPair in sortDictionary) { SortOrder sortOrder = new SortOrder(sortPair.Key, (Order)Enum.Parse(typeof(Order), sortPair.Value)); sortOrderList.Add(sortOrder); } SolrQueryResults<T> result = solrOperation.Query(solrQuery, sortOrderList); return result.ToList(); } catch (Exception ex) { throw ex; } } public List<T> QueryByFilter<T>(string filter, int pageIndex, int pageSize) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); QueryOptions queryOptions = new QueryOptions(); queryOptions.Start = pageIndex; queryOptions.Rows = pageSize; if (pageSize > MaxQueryCount) { queryOptions.Rows = MaxQueryCount; } SolrQueryResults<T> result = solrOperation.Query(filter, queryOptions); return result.ToList(); } catch (Exception ex) { throw ex; } } public List<T> QueryByFilter<T>(ISolrQuery solrQuery, int pageIndex, int pageSize) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); QueryOptions queryOptions = new QueryOptions(); queryOptions.Start = pageIndex; queryOptions.Rows = pageSize; if (pageSize > MaxQueryCount) { queryOptions.Rows = MaxQueryCount; } SolrQueryResults<T> result = solrOperation.Query(solrQuery, queryOptions); return result.ToList(); } catch (Exception ex) { throw ex; } } #endregion #region add public int AddEntity<T>(T entity) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Add(entity); solrOperation.Commit(); return 1; } catch (Exception ex) { throw ex; } } public int AddEntityList<T>(List<T> entityList) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.AddRange(entityList); solrOperation.Commit(); return 1; } catch (Exception ex) { throw ex; } } #endregion #region delete public int DeleteByEntity<T>(T entity) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Delete(entity); return 1; } catch (Exception ex) { throw ex; } } public int DeleteByKey<T>(string key) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Delete(key); return 1; } catch (Exception ex) { throw ex; } } public int DeleteByEntityList<T>(List<T> entityList) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Delete(entityList); return 1; } catch (Exception ex) { throw ex; } } public int DeleteByKeyList<T>(List<string> keyList) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Delete(keyList); return 1; } catch (Exception ex) { throw ex; } } public int DeleteByFilter<T>(ISolrQuery query) { try { ISolrOperations<T> solrOperation = GetSolrOperation<T>(); solrOperation.Delete(query); return 1; } catch (Exception ex) { throw ex; } } #endregion #endregion } }
这里面主要是Solr的增删改查方法,需要说的下面的这个方法
private static void RegisterSolrInstance() { string path = AppDomain.CurrentDomain.BaseDirectory + @"\SolrConfig\SolrConfig.xml"; SolrCollection solrCollection = Deserialize<SolrCollection>(path); Type startUpType = typeof(Startup); foreach (SolrConfigs solrConfig in solrCollection.SolrConfigs) { foreach (SchemaInfo schema in solrConfig.Schemas) { MethodInfo method = startUpType.GetMethod("Init", new Type[] { typeof(string) }) .MakeGenericMethod(Type.GetType(schema.EntityType)); method.Invoke(null, new object[] { solrConfig.BaseAddress + schema.ServiceName }); } } }
就是我们第一次使用SolrHelper的时候,将配置文件中所有的Solr实例都进行注册,用的时候我们只需要通过下面的代码获取即可
private ISolrOperations<T> GetSolrOperation<T>() { return ServiceLocator.Current.GetInstance<ISolrOperations<T>>(); }
接下来看我们的SolrCollection类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; namespace SolrCURDDemo { [XmlRoot("SolrConfigCollection")] public class SolrCollection { [XmlElement("SolrConfigs")] public SolrConfigs[] SolrConfigs; } public class SolrConfigs { [XmlElement("Schema")] public SchemaInfo[] Schemas; [XmlAttribute("baseAddress")] public string BaseAddress; } public class SchemaInfo { [XmlAttribute("name")] public string ServiceName; [XmlAttribute("entityName")] public string EntityType; } }
对应于我们的SolrConfig.xml文件,用于反序列化,结合SolrHelper中的Desrialize方法就能明白了。
OK,我们的窗体如下
OK,我们看一下保存代码很简单,如下
UserInfoEntity userInfoEntity = new UserInfoEntity(); userInfoEntity.UserNo = userNo; userInfoEntity.Name = name; userInfoEntity.Age = age; userInfoEntity.IsMarried = isMarried; int suc = SolrHelper.GetInstance().AddEntity<UserInfoEntity>(userInfoEntity);
保存成功后,我们先在Solr中查询,结果如下
接着我们在Demo中查询,代码如下
string filter = this.txtFilter.Text.Trim(); if (filter == string.Empty) { CommonMessage.ShowMessage(Resources.Msg_Input_Filter); return; } try { List<UserInfoEntity> userInfoList = SolrHelper.GetInstance().QueryByFilter<UserInfoEntity>(filter); this.dgvSearchResult.DataSource = userInfoList; this.BuildRowNumber(); } catch (Exception ex) { CommonMessage.ShowMessage(ex.Message); }
可以查询出结果
在得到这样的结果我不得不说,我上面的SolrConfig配置文件的内容应该是这样的
<?xml version="1.0" encoding="utf-8" ?> <SolrConfigCollection> <SolrConfigs baseAddress="Http://192.168.192.128:8080/solr/MyTest."> <Schema name="UserInfo" entityName="SolrCURDDemo.UserInfoEntity"></Schema> </SolrConfigs> <!--<SolrConfigs baseAddress="Http://192.168.192.128:8080/solr/MyOtherTest."> <Schema name="UserInfo"></Schema> </SolrConfigs>--> </SolrConfigCollection>
但是不知道怎么回事,我想改上面的地址,因为我少了/solr。但是51cto这个编辑器在chrome和IE9下没办法修改,甚至是我想整个删除都不行,郁闷了,再给大家贴一次。
我们再看看删除的代码
string userNo = txtUserNo.Text.Trim(); if (userNo == string.Empty) { CommonMessage.ShowMessage(Resources.Msg_InputUserNo); return; } int suc = SolrHelper.GetInstance().DeleteByKey<UserInfoEntity>(userNo);
OK,这个删除是根据主键删除,还有根据实体删除,查询条件删除。看看SolrHelper类中的方法你就清楚了。在这里给大家推荐几个网站
http://en.wikipedia.org/wiki/Apache_Solr
大家去学吧!
最后我想说的是大家下载solrNet的时候不要去官网下载,不知道怎么回事,官网的SolrNet-0.4.0.xx版本有问题,提交保存数据之后会报400错误,但是数据能保存进去,需要重启tomcat才能看到。所以建议大家去GitHub下载。GitHub链接地址:https://github.com/mausch/SolrNet。
官网地址:http://code.google.com/p/solrnet/