热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Solr入门和实践以及我对Solr的8点理解

友情提示Solr的内容还是比较多的,一篇文章只能讲解一部分。全面介绍,没兴趣,没时间,也没能力,回报还不大。本文只写点我认为比较重要的知识点,独特的个人想法。仅供参考哦,更多细节需要自己去


友情提示
Solr的内容还是比较多的,一篇文章只能讲解一部分。
全面介绍,没兴趣,没时间,也没能力,回报还不大。
本文只写点我认为比较重要的知识点,独特的个人想法。
仅供参考哦,更多细节需要自己去琢磨。


概述
Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,
同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。


工作方式
文档通过Http利用XML 加到一个搜索集合中。
查询该集合也是通过http收到一个XML/JSON响应来实现。
它的主要特性包括:高效、灵活的缓存功能,垂直搜索功能,高亮显示搜索结果,通过索引复制来提高可用性,
提供一套强大Data Schema来定义字段,类型和设置文本分析,提供基于Web的管理界面等。


需求场景
  查询和搜索,我们直接查询数据库MySQL。查询数据库主要有一些局限性:
比如多表查询效率低,大文本字段不好建立索引和搜索,复杂的条件查询和搜索功能不够强大,或者说不够简单。
  使用Solr的话,就很简单地解决了以上问题。
  
  以上需求,或者说关系型数据库mysql的问题,只是目前的一点理解。
  虽说能够使用MySQL和Sorl解决实际中的问题,但毕竟都是中低难度的问题(自认为如此哦)。
  非要说深入理解,剖析Solr的好处,MySQL是否“干的过”Solr,真心不懂。
  单独搞MySQL,够你研究5年以上,DBA毕竟是个传说。
  Solr,想搞懂,也得好多年。
  
  个人同时学习Java服务端、Android、iOS、Web前端,目标是能够解决工作中最常见的问题,并不想要
深入学习有限的几种技术,比如MySQL,达到那种“再难的问题,也可以搞定”的程度。


我对Solr的8点理解
1.定义数据源接口,获得数据。

  比如定义MySQL查询语句,把一个表或多个表的数据,导入到Solr中。
  这个地方我觉得特别“不公平”,数据都是从别的地方搞过来的。外界的数据如果会变化,意味着,必须处理“数据同步”。
  实时性要求不高的情况下,可以每天“全量更新”。要求高的情况下,单条数据的变化,需要“实时更新-单条”。
  因此,Solr和Mysql并不是“直接竞争”关系,而是“互补”的关系。
2.把Mysql等数据源的数据,导入到Solr中去。
  Solr定义数据,可以理解成一张很大的表,包含了很多字段,比如可以包含mysql中3个表的所有字段。
  这样,查询就不存在“多表”的问题。
  既然是一张表,建立索引,查询就很快了。
3.自带缓存功能。
  Mysql,Solr,Redis等数据源或者有能力获得数据和管理数据的组件,只要需要,就可以提供“缓存”功能。
  Solr简化了查询,缓存就更容易了。
4.索引和全文搜索。
  Solr底层采用Lucene建立索引,全文索引,这样可以实现更多的“搜索功能”,可以说增强了Mysql的查询。
5.站内搜索的另外一种形式。
  百度等搜索引擎,可以为网站提供“站内搜索”功能,他们爬去数据可以是公开的URL的形式。
  如果需要和百度等合作,可以申请使用百度的搜索API,将站内数据,更友好,更快速地告诉百度。
  而Solr和百度提供的搜索相关接口就基本一样,只不过是处在我们的管理之下。
6.简洁使用的管理界面。
  后台有Web界面,导入数据,更新,可以通过可视化的操作来管理,比较方便。
7.功能服务化。
  Solr提供的查询等功能,有Java等多种语言的实现。
  建立数据结构,导入数据,维护缓存和实时性,最重要的就是“查询”和“搜索”了。
8.最大的“隐患”。
  只用Mysql管理数据和查询的时候,我们必须并且只需要保障mysql的“高可用性”。
  不能出任何问题,如果只用1个Mysql,意味着我们需要实时监控Mysql是否可用,如果出了问题,我们需要立即修复它。
  如果是多台Mysql,我们需要用主从,或者更复杂的主从。
  
  现在用了Solr,意味着,我们很多查询和搜索,优先使用Solr,不再使用Mysql。
  这个时候,为了“高可靠性”,我们也必须保障Solr是靠谱的。
  单台Solr服务器,可靠性怎么样,我不太清楚。
  无论单台Solr是否靠谱,多台Solr更加靠谱,这都意味着
  “我们程序中必须可靠的基础服务更多了”。
  
  常见的必须“高可用性”的服务有
  a.Mysql
  b.Redis
  3.Nginx
  4.Solr
  高可用性的服务越多,意味着我们的程序越复杂。
  大部分的公司,都是中小型企业。
  大部分的应用,都是为了快速推出,看看是否有效果。
  真正需要保障“高可靠性”的项目,是很少的,如果遇到了,是很幸运的。
  
  官方网站:http://lucene.apache.org/solr/
 本地环境:Windows-5.3.1版本
 
 运行和建立工程
 启动:solr.cmd start(类似这样)
 建立工程:
name=raikou
cOnfig=solrconfig.xml
schema=schema.xml
dataDir=J\:\\SoftData\\Solr\\raikou\\data
指定config、schema等多种参数。
(图文并茂的入门指引,可以参考其它博主的文章,本人觉得这种“图文并茂”的太尼玛费事了。
方便了读者,但是“技术含量”不够高,博主表示不过瘾o(︶︿︶)o )


简要介绍下几个配置,附带源文件内容


core.properties
name=raikou(项目名称)cOnfig=solrconfig.xml(Solr配置)
schema=schema.xml(模式定义)
dataDir=J\:\\SoftData\\Solr\\raikou\\data (存储索引等数据)




Web界面输入的内容,保存在这了,入口配置,可以这么说。


schema.xml
                


   定义了几个字段


  id
 title
  唯一字段,默认查询字段
  
  schemal.xml还配置了若干其它配置文件,比如“stopwords_en.txt”、“protwords.txt”、“stopwords.txt”等。
  如果Solr启动报错,可能是缺少了这些字段。
 
data-config.xml 
                                                                              				  				             


  定义了数据导入、增量更新的查询语句。
  
 web.xml 这段配置,可能有用
  E:\Mongodb-Redis-Nginx\solr-5.3.1\server\solr-webapp\webapp\WEB-INF\web.xml
   
              solr/home       J:\SoftData\Solr\       java.lang.String    


  
Java程序访问
  maven配置
    
		org.apache.solr		solr-solrj		5.3.1	




包名:org.apache.solr.client.solrj


工具类
SolrHelper.java 查询(查询语句构造和执行查询,分页查询),更新,重建索引

import java.beans.PropertyDescriptor;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date;import java.util.List;import org.apache.commons.lang3.StringUtils;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrInputDocument;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.github.pagehelper.Page;/**查询(查询语句构造),更新,重建索引*/public class SolrHelper {	protected final Logger logger = LoggerFactory.getLogger(SolrHelper.class);	private HttpSolrClient server;	private StringBuffer queryString;	public SolrHelper(String reqUrl) {		server = new HttpSolrClient(reqUrl);		queryString = new StringBuffer();	}	public void andEquals(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":").append(val);	}	public void orEquals(String fieldName, String val) {		queryString.append(" || ").append(fieldName).append(":").append(val);	}	public void andNotEquals(String fieldName, String val) {		queryString.append(" && ").append("-").append(fieldName).append(":")				.append(val);	}	public void orNotEquals(String fieldName, String val) {		queryString.append(" || ").append("-").append(fieldName).append(":")				.append(val);	}	public void andGreaterThan(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append(val)				.append(" TO ").append("*]");	}	public void orGreaterThan(String fieldName, String val) {		queryString.append(" || ").append(fieldName).append(":[").append(val)				.append(" TO ").append("*]");	}	public void andGreaterThanOrEqualTo(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append(val)				.append(" TO ").append("*]");	}	public void orGreaterThanOrEqualTo(String fieldName, String val) {		queryString.append(" || ").append(fieldName).append(":[").append(val)				.append(" TO ").append("*]");	}	public void andDateGreaterThan(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[")				.append(formatUTCString(val)).append(" TO ").append("*]");	}	public void orDateGreaterThan(String fieldName, Date val) {		queryString.append(" || ").append(fieldName).append(":[")				.append(formatUTCString(val)).append(" TO ").append("*]");	}	public void andDateGreaterThanOrEqualTo(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[")				.append(formatUTCString(val)).append(" TO ").append("*]");	}	public void orDateGreaterThanOrEqualTo(String fieldName, Date val) {		queryString.append(" || ").append(fieldName).append(":[")				.append(formatUTCString(val)).append(" TO ").append("*]");	}	public void andLessThan(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(val).append("]");	}	public void orLessThan(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(val).append("]");	}	public void andLessThanOrEqualTo(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(val).append("]");	}	public void orLessThanOrEqualTo(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(val).append("]");	}	public void andDateLessThan(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(formatUTCString(val)).append("]");	}	public void orDateLessThan(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(formatUTCString(val)).append("]");	}	public void andDateLessThanOrEqualTo(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(formatUTCString(val)).append("]");	}	public void orDateLessThanOrEqualTo(String fieldName, Date val) {		queryString.append(" && ").append(fieldName).append(":[").append("*")				.append(" TO ").append(formatUTCString(val)).append("]");	}	public void andLike(String fieldName, String val) {		queryString.append(" && ").append(fieldName).append(":*").append(val)				.append("*");	}	public void orLike(String fieldName, String val) {		queryString.append(" || ").append(fieldName).append(":*").append(val)				.append("*");	}	public void andNotLike(String fieldName, String val) {		queryString.append(" && ").append("-").append(fieldName).append(":*")				.append(val).append("*");	}	public void orNotLike(String fieldName, String val) {		queryString.append(" || ").append("-").append(fieldName).append(":*")				.append(val).append("*");	}	public void andIn(String fieldName, String[] vals) {		queryString.append(" && ");		in(fieldName, vals);	}	private void in(String fieldName, String[] vals) {		List list=Arrays.asList(vals);		in(queryString,fieldName,list);	}		public void orIn(String fieldName, List vals) {		queryString.append(" || ");		in(queryString,fieldName,vals);	}	private static void in(StringBuffer queryString,String fieldName, List vals) {		queryString.append("(");		inStr(queryString, fieldName, vals);		queryString.append(")");	}	private static void inStr(StringBuffer queryString, String fieldName,			List vals) {		int index = 0;		for (String val : vals) {			if (0 != index) {				queryString.append(" || ");			}			queryString.append(fieldName).append(":").append(val);			index++;		}	}		// http://stackoverflow.com/questions/634765/using-or-and-not-in-solr-query	//instead of "NOT [condition]" use "(*:* NOT [condition])"	public void andNotIn(String fieldName, String[] vals) {		List list=Arrays.asList(vals);		queryString.append("&&(");		queryString.append("*:* NOT ");		inStr(queryString, fieldName, list);		queryString.append(")");	}	public void andDateBetween(String fieldName, Date startDate, Date endDate) {		queryString.append(" && ").append(fieldName).append(":[")				.append(formatUTCString(startDate)).append(" TO ")				.append(formatUTCString(endDate)).append("]");	}	public void orDateBetween(String fieldName, Date startDate, Date endDate) {		queryString.append(" || ").append(fieldName).append(":[")				.append(formatUTCString(startDate)).append(" TO ")				.append(formatUTCString(endDate)).append("]");	}	public void andDateNotBetween(String fieldName, Date startDate, Date endDate) {		queryString.append(" && ").append("-").append(fieldName).append(":[")				.append(formatUTCString(startDate)).append(" TO ")				.append(formatUTCString(endDate)).append("]");	}	public void orDateNotBetween(String fieldName, Date startDate, Date endDate) {		queryString.append(" && ").append("-").append(fieldName).append(":[")				.append(formatUTCString(startDate)).append(" TO ")				.append(formatUTCString(endDate)).append("]");	}	public void andBetween(String fieldName, String start, String end) {		queryString.append(" && ").append(fieldName).append(":[").append(start)				.append(" TO ").append(end).append("]");	}	public void orBetween(String fieldName, String start, String end) {		queryString.append(" || ").append(fieldName).append(":[").append(start)				.append(" TO ").append(end).append("]");	}	public void andNotBetween(String fieldName, String start, String end) {		queryString.append(" && ").append("-").append(fieldName).append(":[")				.append(start).append(" TO ").append(end).append("]");	}	public void orNotBetween(String fieldName, String start, String end) {		queryString.append(" || ").append("-").append(fieldName).append(":[")				.append(start).append(" TO ").append(end).append("]");	}	public void andStartSub() {		queryString.append(" && (");	}	public void orStartSub() {		queryString.append(" || (");	}	public void endSub() {		queryString.append(")");	}	private String formatUTCString(Date d) {		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");		String s = sdf.format(d);		return s;	}	public int execQueryTotalCount() {		SolrQuery params = handleQuery();		params.set("start", 0);		params.set("rows", Integer.MAX_VALUE);		QueryResponse respOnse= null;		try {			respOnse= server.query(params);			return response.getResults().size();		} catch (SolrServerException e) {			logger.error("", e);		} catch (IOException e) {			logger.error("", e);		}		return 0;	}	public List query(String sort, Class beanClass) {		SolrQuery params = handleQuery();		QueryResponse respOnse= null;		List list = null;		try {			logger.info("SolyQuery:" + params.toString());			respOnse= server.query(params);			list = (List) response.getBeans(beanClass);		} catch (SolrServerException e) {			logger.error("SolrServerException", e);		} catch (IOException e) {			logger.error("IOException", e);		}		return list;	}	public Page execQuery(Integer pageNo, Integer rows, String sort,			Class beanClass) {		List results = null;		Page page = null;		SolrQuery params = handleQuery();		if (pageNo != null && rows != null && pageNo > 0 && rows > 0) {			params.set("start", (pageNo - 1) * rows);			params.set("rows", rows);		}		if (null != sort && !"".equals(sort)) {			params.set("sort", sort);		}		QueryResponse respOnse= null;		try {			logger.info("SolyQuery WithPage:" + params.toString());			respOnse= server.query(params);			results = (List) response.getBeans(beanClass);			page = new Page(pageNo, rows, execQueryTotalCount());			page.addAll(results);		} catch (SolrServerException e) {			logger.error("SolrServerException", e);		} catch (IOException e) {			logger.error("IOException", e);		}		return page;	}	private SolrQuery handleQuery() {		SolrQuery params = new SolrQuery();		String qryFinalStr = queryString.toString();		if (qryFinalStr.startsWith(" && ")) {			qryFinalStr = qryFinalStr.replaceFirst(" && ", "");		} else if (qryFinalStr.startsWith(" || ")) {			qryFinalStr = qryFinalStr.replaceFirst(" || ", "");		}		// 子查询开头的关联符号		if (-1 != qryFinalStr.indexOf("( && ")) {			qryFinalStr = qryFinalStr.replaceAll("\\( \\&\\& ", "(");		}		if (-1 != qryFinalStr.indexOf("( || ")) {			qryFinalStr = qryFinalStr.replaceAll("\\( \\|\\| ", "(");		}		if (StringUtils.isBlank(qryFinalStr)) {			qryFinalStr = "*:*";		}		params.set("q", qryFinalStr);		return params;	}	public void execDelete(String keyName, String keyVal) {		try {			server.deleteByQuery(keyName + ":" + keyVal);			server.commit();		} catch (SolrServerException | IOException e) {			logger.error("", e);		}	}	public void execUpdate(T model) {		Field[] fields = model.getClass().getDeclaredFields();		SolrInputDocument solrDoc = new SolrInputDocument();		try {			for (Field f : fields) {				PropertyDescriptor pd;				pd = new PropertyDescriptor(f.getName(), model.getClass());				// 属性名				String fieldName = f.getName();				Method rM = pd.getReadMethod();// 获得读方法				solrDoc.addField(fieldName, rM.invoke(model));			}			server.add(solrDoc);			server.commit();		} catch (Exception e) {			logger.error("", e);		}	}	public void execUpdate(SolrInputDocument solrDoc) {		try {			server.add(solrDoc);			server.commit();		} catch (SolrServerException e) {			logger.error("", e);		} catch (IOException e) {			logger.error("", e);		}	}	/**	 * 重建索引和增量索引的接口	 * 	 * @param delta	 */	public void buildIndex(boolean delta) {		SolrQuery query = new SolrQuery();		// 指定RequestHandler,默认使用/select		query.setRequestHandler("/dataimport");		String command = delta ? "delta-import" : "full-import";		String clean = delta ? "false" : "true";		String optimize = delta ? "false" : "true";		query.setParam("command", command).setParam("clean", clean)				.setParam("commit", "true").setParam("optimize", optimize);		try {			server.query(query);		} catch (SolrServerException e) {			logger.error("建立索引时遇到错误,delta:" + delta, e);		} catch (IOException e) {			logger.error("建立索引时遇到错误,delta:" + delta, e);		}	}}




代码使用示例:
    1.常见的分页查询,更新单条数据
public static void main(String[] args) {		SolrHelper sh = new SolrHelper(				"http://host/solr/project");		sh.andEquals("id", "32404");		List page = sh.execQuery(1, 10, "id desc",				Project.class);		Project ps = page.get(0);		ps.setTotal(3.1415);		sh.execUpdate(ps);	}



2.不修改,直接同步
public void synProject(long id) {		ProjectSolrDto solrDto = projectMapper.selectSolrProjectSimple(id);		SolrHelper solrHelper = new SolrHelper(				solrProjectUrl);		solrHelper.execUpdate(solrDto);	}



3.同步某几个字段
public void synIntention(Long id) {		Intention intention = intentionMapper.selectByPrimaryKey(id);		SolrHelper solrHelper = new SolrHelper(				solrIntentionUrl);		SolrInputDocument solrDoc = new SolrInputDocument();		solrDoc.addField("id", intention.getId());		solrDoc.addField("intro", intention.getIntro());		solrDoc.addField("industry", intention.getIndustry());		solrHelper.execUpdate(solrDoc);	}	


    4.删除
public void delFund(Long id) {		SolrHelper solrHelper = new SolrHelper(				solrFundUrl);		solrHelper.execDelete("id", id.toString());	}




几点补充
1.需要有“定时器”,定时“全量更新”和“重建索引”,防止数据不一致,或者查询效率低。
2.SolrHelper中的代码,或者说Solr的相关代码,无非就是“增删改查CRUD”,比较特殊的
“重建索引”和为了执行查询,拼接查询条件的“And,Or”等工具方法。
3.分页有个实体类,用到了Github上的1个工具,个人觉得一般般,Page类的定义比较糟糕。
如有需要,自己引入,或者自行改造。


写在最后
IT互联网技术很多,更新很快,问题也很多,深入需要实践,深入需要时间。
技术方面的博学和专注,自己去平衡吧~
技术和技术之外的平衡,自己看着办哦~


更多资料
Solr 搭建搜索服务器
http://my.oschina.net/u/1757458/blog/389109?fromerr=HUEucn9b


Solr调研总结
http://www.cnblogs.com/guozk/p/3498831.html


Solr中国
http://www.solr.cc/blog/


solr对跨服务器表联合查询的配置
http://blog.csdn.net/awj3584/article/details/10326439
推荐阅读
  • 一:什么是solrSolr是apache下的一个开源项目,使用Java基于lucene开发的全文搜索服务器;Lucene是一个开放源代 ... [详细]
  • es的分布式原理?es是如何实现分布式的?
    Elasticsearch设计的理念是分布式搜索引擎,底层其实是基于lucene。核心思 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了Composer依赖管理的重要性及使用方法。对于现代语言而言,包管理器是标配,而Composer作为PHP的包管理器,解决了PEAR的问题,并且使用简单,方便提交自己的包。文章还提到了使用Composer能够避免各种include的问题,避免命名空间冲突,并且能够方便地安装升级扩展包。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • camel_使用Camel在来自不同来源的Solr中索引数据
    camelApacheSolr是建立在Lucene之上的“流行的,快速的开源企业搜索平台”。为了进行搜索(并查找结果),通常需要从不同的源(例如内容管理 ... [详细]
author-avatar
彬彬521521
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有