.NET开发过程中的全文索引使用技巧之Solr(转)

前言:相信许多人都听说过.net开发过程中基于Lucene.net实现的全文索引,而Solr是一个高性能,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引引擎,这里我就绕过Lucene,直接说Solr的应用了,总之,Solr比Lucene更加方便简洁好用,而且上手快,开发效率高。

   Solr应用场景:涉及到大数据的全文搜索。尤其是电子商务平台还有现在流行的云计算,物联网等都是需要强大的数据量作为支撑的,使用Solr来进行数据 检索最合适不过了,而且Solr是免费开源的,门槛低、投资少见效快。关于Solr的一些优点我这里就不在累赘陈述了,园子里也有很多大神也写了很多关于 Solr的技术博文,我这里也只是抛砖引玉,见笑了。

   好了,这里就开始Solr的奇幻之旅吧

基于.NET平台下的Solr开发步骤

一、搭建Solr服务器,具体步骤如下:

   1.安装JDK,因为是.NET平台,不需要安装JRE、JAVA虚拟机,只安装JDK即可,而且安装JDK不需要手动去配置环境变量,它会自动帮我们配置好环境变量,很方便,这里我安装的是jdk1.7,官网地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html

   2.安装Tomcat8.0,官网地址:http://tomcat.apache.org/download-80.cgi,安装完成后启动Monitor Tomcat,浏览器地址栏输入http://localhost:8080/,能进入说明安装成功

   3.下载Solr,这里我用的是Solr4.4版本,下载后进行下列配置

  (1)解压Solr4.4,创建Solr目录,比如D:/SorlServer/one,将解压后的Solr4.4中的example目录下的Solr文件夹中的所有文件拷贝到创建的目录中

  (2)创建Solr Web应用,具体步骤,将解压后的Solr4.4中的dist目录下的Solr-4.4.0.war文件拷贝到Tomcat下,比如C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps下,重命名为one.war,启动Tomcat后该文件会自动解压,进入到D:\SorlServer\one\collection1\conf下,打开solrconfig.xml文件,找到 <dataDir>节点改为<dataDir>${solr.data.dir:c:/SorlServer/one/data}</dataDir>

注意:这一步很重要:打开C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\One\WEB-INF下的web.xml文件,找到<env-entry>节点开启,

将env-entry-value值改为D:/SorlServer/one,如下:

<env-entry>

<env-entry-name>solr/home</env-entry-name>

<env-entry-value>D:/SorlServer/one</env-entry-value>

<env-entry-type>java.lang.String</env-entry-type>

</env-entry>

   (3)将解压后的Solr4.4下的/dist/solrj-lib目录中的所有jar包拷贝到C:\Program Files\Apache Software Foundation\Tomcat 7.0\lib中

  (4)停止Tomcat,然后再启动,访问http://localhost:8080/one,即可打开

注意:如果是开发英文网站,我们就不需要使用第三方的分词配置,Solr本身就内置支持英文分词,如果是其他语种比如小语种(日语、意大利、法语等等),大家可以去网上找相关的分词包,这里我们以中文分词为例,毕竟国内大部分网站都是中文为主的。

   4.配置中文分词,国内常用的分词器(庖丁解牛mmseg4jIKAnalyzer),这里我用的是IKAnalyzer,这个分词器比较活跃而且更新也快,挺好用的,具体步骤如下:

(1)将IKAnalyzer的jar包以及IKAnalyzer.cfg.xml都复制到C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\one\WEB-INF\lib下

(2)配置D:\SorlServer\one\collection1\conf下的schema.xml,添加如下配置:

<!-- 分词配置 -->

<fieldType name="text_IKFENCHI" class="solr.TextField">

<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>

</fieldType>

(3)停止Tomcat,然后再启动,访问http://localhost:8080/one/#/collection1/analysis,即可进行测试

以上是Solr服务器端的相关配置工作

二、开始基于.NET平台的Solr开发:

   1.下载Solr客户端组件,我用的是园子里的Terry大哥的EasyNet.Solr,地址在微软开源站:http://easynet.codeplex.com/

Terry大哥已经把solr客户端封装的很完善了,里面封装了很多现成的方法和参数配置,我们直接可以拿过来用,利用Easynet.solr创建索引,然后再查询索引,具体使用方法如下:

  (1)下载EasyNet.Solr源码直接放到项目中,也可以将源码生成Dll组件后添加到项目引用进行使用,把源码放到项目中最好不过了,我们也可以对其进行调整来满足自己的需要

  (2)创建索引实体类,就是我们要保存的索引数据,比如创建一个产品实体类 

using System;
using System.Collections.Generic;

namespace Seek.SearchIndex
{
    public partial class IndexProductModel
    {
        public IndexProductModel()
        {
        }

        #region  Properties
        public int ID { get; set; }
        public int ProductID { get; set; }
        public string ClassPath { get; set; }
        public int ClassID1 { get; set; }
        public int ClassID2 { get; set; }
        public int ClassID3 { get; set; }
        public string Title { get; set; }
        public string Model { get; set; }
        public string PriceRange { get; set; }
        public string AttributeValues { get; set; }
        public string ProductImages { get; set; }
        public int MemberID { get; set; }
        public System.DateTime CreateDate { get; set; }
        public System.DateTime LastEditDate { get; set; }
        public string FileName { get; set; }
        public string ProductType { get; set; }
        public string Summary { get; set; }
        public string Details { get; set; }
        public string RelatedKeywords { get; set; }
        public int MemberGrade { get; set; }
        #endregion
    }
}

(3)配置Solr服务器端的xml,就是将咱们的这个索引实体类配置到Solr服务器上,进入D:\SorlServer\one\collection1\conf,打开schema.xml文件,配置如下

<field name="ID" type="string" indexed="true" stored="true" required="true" multiValued="false" />
   <field name="ProductID" type="int" indexed="true" stored="true"/>
   <!-- 快速高亮配置 termVectors="true" termPositions="true"  termOffsets="true" -->
   <field name="Title" type="text_en_splitting" indexed="true" stored="true" termVectors="true" termPositions="true"  termOffsets="true"/>
   <field name="Model" type="text_en_splitting" indexed="true" stored="true" termVectors="true" termPositions="true"  termOffsets="true"/>
   <field name="ClassPath" type="string" indexed="true" stored="true"/>
   <field name="ClassID1" type="int" indexed="true" stored="true"/>
   <field name="ClassID2" type="int" indexed="true" stored="true"/>
   <field name="ClassID3" type="int" indexed="true" stored="true"/>
   <field name="PriceRange" type="string" indexed="true" stored="true"/>
   <field name="AttributeValues" type="string" indexed="true" stored="true"/>
   <field name="ProductImages" type="string" indexed="true" stored="true"/>
   <field name="MemberID" type="int" indexed="true" stored="true"/>
   <field name="CreateDate" type="date" indexed="true" stored="true"/>
   <field name="LastEditDate" type="date" indexed="true" stored="true"/>
   <field name="FileName" type="string" indexed="true" stored="true"/>
   <field name="ProductType" type="string" indexed="true" stored="true"/>
   <field name="Summary" type="string" indexed="true" stored="false"/>
   <field name="Details" type="string" indexed="true" stored="false"/>
   <field name="RelatedKeywords" type="string" indexed="true" stored="true"/>
   <field name="MemberType" type="string" indexed="true" stored="true"/>
   <field name="MemberGrade" type="int" indexed="true" stored="true"/>

 (4)开始创建索引,最好能写一个生成索引的客户端程序,我这里提供一下自己的索引器关键代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Seek.SearchIndex;
using System.Data;
using System.Threading;
using System.Configuration;
using System.Reflection;
using EasyNet.Solr;
using EasyNet.Solr.Impl;
using EasyNet.Solr.Commons;
using System.Xml.Linq;
using EasyNet.Solr.Commons.Params;
using System.Threading.Tasks;

namespace Seek.SearchIndex
{
    /// <summary>
    /// 索引器
    /// </summary>
    public class Indexer
    {
        private readonly static OptimizeOptions optimizeOptions = new OptimizeOptions();
        private readonly static CommitOptions commitOptions = new CommitOptions() { SoftCommit = true };
        private readonly static ISolrResponseParser<NamedList, EasyNet.Solr.ResponseHeader> binaryResponseHeaderParser = new BinaryResponseHeaderParser();
        private readonly static IUpdateParametersConvert<NamedList> updateParametersConvert = new BinaryUpdateParametersConvert();
        private readonly static ISolrQueryConnection<NamedList> connection = new SolrQueryConnection<NamedList>() { ServerUrl = ConfigurationManager.AppSettings["SolrServer"] };
        private readonly static ISolrUpdateConnection<NamedList, NamedList> solrUpdateConnection = new SolrUpdateConnection<NamedList, NamedList>() { ServerUrl = ConfigurationManager.AppSettings["SolrServer"], ContentType = "application/javabin" };
        private readonly static ISolrUpdateOperations<NamedList> solr = new SolrUpdateOperations<NamedList, NamedList>(solrUpdateConnection, updateParametersConvert) { ResponseWriter = "javabin" };
        private readonly static ISolrQueryOperations<NamedList> solrQuery = new SolrQueryOperations<NamedList>(connection) { ResponseWriter = "javabin" };

        public enum State
        {
            /// <summary>
            /// 运行中
            /// </summary>
            Runing,
            /// <summary>
            /// 停止
            /// </summary>
            Stop,
            /// <summary>
            /// 中断
            /// </summary>
            Break
        }
        /// <summary>
        /// 窗口
        /// </summary>
        private Main form;
        /// <summary>
        /// 线程
        /// </summary>
        public Thread t;
        /// <summary>
        /// 消息状态
        /// </summary>
        public State state = State.Stop;
        /// <summary>
        /// 当前索引
        /// </summary>
        private long currentIndex = 0;

        public long CurrentIndex
        {
            get { return currentIndex; }
            set { currentIndex = value; }
        }

        private int _startId = AppCongfig.StartId;

        public int StartId
        {
            get { return _startId; }
            set { _startId = value; }
        }

        /// <summary>
        /// 产品总数
        /// </summary>
        private int productsCount = 0;
        /// <summary>
        /// 起始时间
        /// </summary>
        private DateTime startTime = DateTime.Now;
        /// <summary>
        /// 结束时间
        /// </summary>
        private DateTime endTime = DateTime.MinValue;
        private static object syncLock = new object();
        #region 单利模式
        private static Indexer instance = null;

        private Indexer(Main _form)
        {
            form = _form;
            productsCount = DataAccess.GetCount(0);       //产品数统计
            form.fullerTsslMaxNum.Text = productsCount.ToString();
            form.fullerProgressBar.Minimum = 0;
            form.fullerProgressBar.Maximum = productsCount;
        }
        public static Indexer GetInstance(Main form)
        {
            if (instance == null)
            {
                lock (syncLock)
                {
                    if (instance == null)
                    {
                        instance = new Indexer(form);
                    }
                }
            }
            return instance;
        }
        #endregion

        /// <summary>
        /// 启动
        /// </summary>
        public void Start()
        {
            ThreadStart ts = new ThreadStart(FullerRun);
            t = new Thread(ts);
            t.Start();
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            state = State.Stop;
        }
        /// <summary>
        /// 中断
        /// </summary>
        public void Break()
        {
            state = State.Break;
        }

        /// <summary>
        /// 创建索引
        /// </summary>
        public void InitIndex(object data)
        {
            var docs = new List<SolrInputDocument>();
            DataTable list = data as DataTable;
            foreach (DataRow pro in list.Rows)
            {
                var model = new SolrInputDocument();

                PropertyInfo[] properites = typeof(IndexProductModel).GetProperties();//得到实体类属性的集合
                string[] dateFields = { "CreateDate", "LastEditDate" };
                string field = string.Empty;//存储fieldname
                foreach (PropertyInfo propertyInfo in properites)//遍历数组
                {
                    object val = pro[propertyInfo.Name];
                    if (val != DBNull.Value)
                    {
                        model.Add(propertyInfo.Name, new SolrInputField(propertyInfo.Name, val));
                    }
                }
                docs.Add(model);

                StartId = Convert.ToInt32(pro["ID"]);
            }
            GetStartId();
            lock (syncLock)
            {
                if (currentIndex <= productsCount)
                {
                    form.fullerProgressBar.Value = (int)currentIndex;
                }
                form.fullerTsslCurrentNum.Text = currentIndex.ToString();
            }
            var result = solr.Update("/update", new UpdateOptions() {  Docs = docs });
        }

        /// <summary>
        /// 创建索引
        /// </summary>
        public void CreateIndexer(DataTable dt)
        {
            GetStartId();
            Parallel.ForEach<DataRow>(dt.AsEnumerable(), (row) =>
            {
                //从数据库查询商品详细属性
                if (row != null)
                {
                    var docs = new List<SolrInputDocument>();
                    var model = new SolrInputDocument();

                    PropertyInfo[] properites = typeof(IndexProductModel).GetProperties();//得到实体类属性的集合
                    string[] dateFields = { "CreateDate", "LastEditDate" };
                    string field = string.Empty;//存储fieldname
                    foreach (PropertyInfo propertyInfo in properites)//遍历数组
                    {
                        object val = row[propertyInfo.Name];
                        if (val != DBNull.Value)
                        {
                            model.Add(propertyInfo.Name, new SolrInputField(propertyInfo.Name, val));
                        }
                    }
                    docs.Add(model);

                    StartId = Convert.ToInt32(row["ID"]);
                    var result = solr.Update("/update", new UpdateOptions() { Docs = docs });
                }
            });

            //GetStartId();
            lock (syncLock)
            {
                if (currentIndex <= productsCount)
                {
                    form.fullerProgressBar.Value = (int)currentIndex;
                }
                form.fullerTsslCurrentNum.Text = currentIndex.ToString();
            }
        }

        /// <summary>
        /// 全部索引运行
        /// </summary>
        public void FullerRun()
        {
            //GetStartId();
            //form.fullerTsslCurrentNum.Text = currentIndex.ToString();
            DataTable dt = DataAccess.GetNextProductsInfo(StartId);
            StartId = AppCongfig.StartId;
            if (state == State.Break)
            {
                this.SendMesasge("完全索引已继续,起始ID[" + StartId + "]...");
            }
            else
            {
                startTime = DateTime.Now;
                this.SendMesasge("完全索引已启动,起始ID[" + StartId + "]...");
            }
            state = State.Runing;
            form.btnInitIndex.Enabled = false;
            form.btnSuspend.Enabled = true;
            form.btnStop.Enabled = true;

            while (dt != null && dt.Rows.Count > 0 && state == State.Runing)
            {
                try
                {
                    InitIndex(dt);//单线程
                   // CreateIndexer(dt);//多线程
                }
                catch (Exception ex)
                {
                    state = State.Stop;
                    form.btnInitIndex.Enabled = true;
                    form.btnSuspend.Enabled = false;
                    form.btnStop.Enabled = false;
                    GetStartId();
                    this.SendMesasge(ex.Message.ToString());
                }
                form.fullerTsslTimeSpan.Text = "已运行 :" + GetTimeSpanShow(DateTime.Now - startTime) + ",预计还需:" + GetTimeSpanForecast();

                try
                {
                    dt = DataAccess.GetNextProductsInfo(StartId);//获取下一组产品
                }
                catch (Exception err)
                {
                    this.SendMesasge("获取下一组产品出错,起始ID[" + StartId + "]:" + err.Message);
                }
            }
            if (state == State.Runing)
            {
                state = State.Stop;
                form.btnInitIndex.Enabled = true;
                form.btnSuspend.Enabled = false;
                form.btnStop.Enabled = false;
                AppCongfig.SetValue("StartId", StartId.ToString());
                this.SendMesasge("完全索引已完成,总计索引数[" + currentIndex + "]结束的产品Id" + StartId);
            }
            else if (state == State.Break)
            {
                GetStartId();
                state = State.Break;
                form.btnInitIndex.Enabled = true;
                form.btnSuspend.Enabled = false;
                form.btnStop.Enabled = false;
                AppCongfig.SetValue("StartId", StartId.ToString());
                this.SendMesasge("完全索引已暂停,当前索引位置[" + currentIndex + "]结束的产品Id" + StartId);
            }
            else if (state == State.Stop)
            {
                GetStartId();
                state = State.Stop;
                this.SendMesasge("完全索引已停止,已索引数[" + currentIndex + "]结束的产品Id" + StartId);
                form.btnInitIndex.Enabled = true;
                form.btnSuspend.Enabled = false;
                form.btnStop.Enabled = false;
                AppCongfig.SetValue("StartId", StartId.ToString());
                productsCount = DataAccess.GetCount(StartId);       //产品数统计
                form.fullerTsslMaxNum.Text = productsCount.ToString();
                form.fullerProgressBar.Minimum = 0;
                form.fullerProgressBar.Maximum = productsCount;
            }
            endTime = DateTime.Now;
        }

        /// <summary>
        /// 多线程构建索引数据方法
        /// </summary>
        /// <param name="threadDataParam"></param>
        public void MultiThreadCreateIndex(object threadDataParam)
        {
            InitIndex(threadDataParam);
        }

        /// <summary>
        /// 获取最大的索引id
        /// </summary>
        private void GetStartId()
        {
            IDictionary<string, ICollection<string>> options = new Dictionary<string, ICollection<string>>();
            options[CommonParams.SORT] = new string[] { "ProductID DESC" };
            options[CommonParams.START] = new string[] { "0" };
            options[CommonParams.ROWS] = new string[] { "1" };
            options[HighlightParams.FIELDS] = new string[] { "ProductID" };
            options[CommonParams.Q] = new string[] { "*:*" };
            var result = solrQuery.Query("/select", null, options);
            var solrDocumentList = (SolrDocumentList)result.Get("response");
            currentIndex = solrDocumentList.NumFound;
            if (solrDocumentList != null && solrDocumentList.Count() > 0)
            {
                StartId = (int)solrDocumentList[0]["ProductID"];
                //AppCongfig.SetValue("StartId", solrDocumentList[0]["ProductID"].ToString());
            }
            else
            {
                StartId = 0;
                // AppCongfig.SetValue("StartId", "0");
            }
        }

        /// <summary>
        /// 优化索引
        /// </summary>
        public void Optimize()
        {
            this.SendMesasge("开始优化索引,请耐心等待...");
            var result = solr.Update("/update", new UpdateOptions() { OptimizeOptions = optimizeOptions });
            var header = binaryResponseHeaderParser.Parse(result);
            this.SendMesasge("优化索引耗时:" + header.QTime + "毫秒");
        }

        /// <summary>
        /// 发送消息到界面
        /// </summary>
        /// <param name="message">发送消息到界面</param>
        protected void SendMesasge(string message)
        {
            form.fullerDgvMessage.Rows.Add(form.fullerDgvMessage.Rows.Count + 1, message, DateTime.Now.ToString());
        }
        /// <summary>
        /// 获取时间间隔显示
        /// </summary>
        /// <param name="ts">时间间隔</param>
        /// <returns></returns>
        protected string GetTimeSpanShow(TimeSpan ts)
        {
            string text = "";
            if (ts.Days > 0)
            {
                text += ts.Days + "天";
            }
            if (ts.Hours > 0)
            {
                text += ts.Hours + "时";
            }
            if (ts.Minutes > 0)
            {
                text += ts.Minutes + "分";
            }
            if (ts.Seconds > 0)
            {
                text += ts.Seconds + "秒";
            }
            return text;
        }
        /// <summary>
        /// 获取预测时间
        /// </summary>
        /// <returns></returns>
        protected string GetTimeSpanForecast()
        {
            if (currentIndex != 0)
            {
                TimeSpan tsed = DateTime.Now - startTime;
                double d = ((tsed.TotalMilliseconds / currentIndex) * productsCount) - tsed.TotalMilliseconds;
                return GetTimeSpanShow(TimeSpan.FromMilliseconds(d));
            }
            return "";
        }
    }
}

 (5)运行索引器,创建索引,这里是我的索引器界面,如图

  可以随时跟踪索引生成的情况

  (6)索引创建完毕后,可以进入Solr服务器界面http://localhost:8080/one/#/collection1/query进行测试

以上就是Solr的前期工作,主要是Solr服务器搭建和客户端调用生成索引,后期再对客户端的查询进行详细的说明,下期预告

1.全文搜索,分词配置,以及类似于谷歌和百度那种输入关键字自动完成功能

2.Facet查询

原文地址:https://www.cnblogs.com/cuihongyu3503319/p/9085881.html

时间: 2024-10-28 19:48:07

.NET开发过程中的全文索引使用技巧之Solr(转)的相关文章

iOS开发过程中的一些调试技巧

前言 在开发中一定需要到调试跟踪,但是很多开发者虽然做过很多的项目,但是未必了解开发中有哪些调试命令可以帮助我们开发者更快更好地定位到问题所在. 本篇文章主要是讲解在开发中如何利用LLDB来Debug.首先会讲一些基础知识,主要是帮助新手们学习如何去调试.对于一些比较高级的操作,不会也没有关系,但是如果能够掌握得了的话,会更方便更快速地查找问题. 初步认识LLDB LLDB是XCode内置的为我们开发者提供的调试工具.至于还不懂什么是调试的,百度一下概念吧,笔者也不知如何描述.看看下图吧,应该就

软件开发过程中如何避免争吵?

软件开发过程中,对一个问题有不同意见是很正常的,不同思想的碰撞可以带来进步,但是如果沟通不当,引发争吵,从而延误项目开发进度,就会得不偿失了. 要做到避免争吵,首先得自我反思,自己是不是哪里做得不对,问题没考虑清楚.问题还没明白就去和别人争,就是你的不对了. 其次,要站在别人的角度先想一想问题.是不是PM有难言之隐,公司的压力过大,不能采纳我的建议? 设计师看问题的角度是不是和我不一样?我的代码编写是否规范,有没有给复审测试人员带来麻烦?项目有没有充分考虑并达到用户的需求?在和别人争论前,必须充

android app 开发过程中 对于性能优化的总结

一款手机应用  从开发过程中就要做好 性能优化,这样才能 让用户体验度 提升, 假如 我们打开一个应用 出现卡顿, 不流畅,则会很影响 用户对该应用的态度,产品狗 都很注意这些人机交互方面的 体验. 谷歌官方也是一直在优化 android 系统,不论是  碎片化处理 还是 系能 上面,这方面 ios 就做的比较好,配置比 android 低,但是流畅度却比android高,体验效果更好. 官方推荐方案:http://www.oschina.net/news/60157/android-perfo

iOS开发过程中使用Core Data应避免的十个错误

原文出处: informit   译文出处:cocoachina Core Data是苹果针对Mac和iOS平台开发的一个框架,主要用来储存数据.对很多开发者来说,Core Data比较容易入手,但很难精通,如果没有正确的学习方法,你将很难真正理解它,更不用说精通了.很多开发者常常在这方面犯一些错误,而这篇文章列出了开发者在iOS开发过程中使用Core Data常见的一些错误,并对如何避免这些错误进行了分析.  1.不了解关键术语 对于iOS开发者来说,会使用Core Data是一项必备技能.

软件开发过程中的审查 (Review)

http://blog.csdn.net/horkychen/article/details/5035769 软件开发过程中的审查 (Review) 希望别人做些什么->定义出流程 希望别人做出正确的结果->定义出审查制度 软件开发项目中包括很多的审查动作,贯穿于整个开发过程.个人认为审查主要有以下目的: 1.尽早排查出潜在的问题(Potential Risk/Issue) 经过其他人的参与,以不同的视角提出不同的看法,会有类似头脑风暴的效果,集思广议来查找工程师未能注意的问题. 2.保持良好

OAF开发中一些LOV相关技巧 (转)

原文地址:OAF开发中一些LOV相关技巧 在OAF开发中,LOV的使用频率是很高的,它由两部分构成一是页面上的LOV输入框(如OAMESSageLovInputBean),二是弹出的LOV模式窗口(OAListOfValueBean).用户选择LOV的按钮就会弹出LOV窗口,用户在LOV窗口查询并选择了值,可以返回到页面上的LOV输入框.在这里就不赘述如何创建LOV,只说一些平时会碰到的应用: 1.控制LOV的查询结果 2.LOV相关事件 3.动态LOV 4.LOV Choice一,控制LOV的

Handlebars.js循环中索引(@index)使用技巧(访问父级索引)

使用Handlebars.js过程中,难免会使用循环,比如构造数据表格.而使用循环,又经常会用到索引,也就是获取当前循环到第几次了,一般会以这个为序号显示在页面上. Handlebars.js中获取循环索引很简单,只需在循环中使用{{@index}}即可. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <META http-equiv=Content-Type content="text/html; charset=utf-

net开发过程中Bin目录net开发过程中Bin目录下面几种文件

.net开发过程中Bin目录下面几种文件格式的解释 在.NET开发中,我们经常会在bin目录下面看到这些类型的文件: .pdb..xsd..vshost.exe..exe..exe.config..vshost.exe.config 项目发布的时候,往往搞不清楚哪些是需要的,那些是不需要的.那么这些格式的文件到底是干什么用的呢? pdb .pdb文件,是VS生成的用于调试的符号文件(program database),保存着调试的信息.在VS的工程属性,C/C++,调试信息格式,设置/Zi,那么

软件开发过程中要主要的问题

结合软件开发生命周期,软件开发过程中应注意的问题如下(个人愚见) 1)明确项目概况,即将项目定位,要结合需求和技术实现,对项目进行准确定位,制定合理的项目开发计划. 2)面对需求变化,需求变化是软件开发过程经常碰到的问题也是致命的问题,排除客户的问题,需求分析要做的足够好,需求分析做好后,最好要客户确认签字. 3)模块划分,把软件系统按照任务需求或者数据模型进行模块划分,提高系统开发进度. 4)编码规范,项目编写代码过程中要有详细的编码规范,如合理的程序文件结构(每个程序文件应由标题.内容.附加