??xml version="1.0" encoding="utf-8" standalone="yes"?> UML是一U通用的徏模语aQ其表达能力相当的强Q不仅可以用于Y件系l的建模Q而且可用于业务徏模以及其它非软gpȝ建模。UMLl合了各U面向对象方法与表示法的优点Q至提出之日起就受到了广泛的重视q得C工业界的支持? 本章按视图、模型元素、图以及公共机制依次介绍UML的构造和基本元素Q以使得读者对UML有一个M了解Q其具体l节在后箋章节中详l描q?/p> d工具QeDraw、jude Ƣ迎大家l箋支持和关注我的博客: http://blog.csdn.net/IBM_hoojo 也欢q大家和我交、探讨IT斚w的知识?/p> emailQ?a href="mailto:hoojo_@126.com">hoojo_@126.com 如果你觉得本文不错的话,请你点击屏幕右下方的 1. UML的组?/font> UMLp?View)、图(Diagram)?a name="OLE_LINK13">模型元素(Model Element)?a name="OLE_LINK14">通用机制(General Mechanism){几个部分组成? a) 视图(View)Q?是表辄l的某一斚w的特征的UML建模元素的子集,由多个图构成Q是在某一个抽象层上,对系l的抽象表示? b) ?Diagram)Q?是模型元素集的图形表C,通常是由弧(关系Q和点Q其他模型元素)怺q接构成的? c) 模型元素(Model Element)Q代表面向对象中的类、对象、消息和关系{概念,是构成图的最基本的常用概c? d) 通用机制(General Mechanism)Q用于表C其他信息,比如注释、模型元素的语义{。另外,UMLq提供扩展机Ӟ使UML语言能够适应一个特D的ҎQ或q程Q,或扩充至一个组l或用户? 2. UML视图的分c?/font> UML是用来描q模型的Q用模型来描q系l的机构或静态特征,以及行ؓ或动态特征。从不同的视角ؓpȝ构架建模QŞ成系l的不同视图? (1) 用例视图(Use Case View)Q?/strong>从用L角度看到的或需要的pȝ功能Q是被称为参与者的外部用户所能观察到的系l功能的模型图? (2) 逻辑视图(Logical View)Q?/strong>展现pȝ的静态或l构l成及特征,也称为结构模型视?Structural Model View)或静态视?Static View)? (3) q发视图(Concurrent View)Q?/strong>体现了系l的动态或行ؓ特征Q也UCؓ行ؓ模型视图(Behavioral Model View)或动态视?Dynamic View)? (4) lg视图(Component View)Q?/strong>体现了系l实现的l构和行为特征,也称为实现模型视?Implementation Model View)? (5) 配置视图(Deployment View)Q?/strong>体现了系l实现环境的l构和行为特征,也称为环境模型视?Environment Model View)或物理视?Physical View)? 视图是由囄?/b>的,UML提供9U不同的图: (1) 用例?/a>(Use Case Diagram)Q描q系l功能; (2) cd(Class Diagram)Q描q系l的静态结构; (3) 对象?Object Diagram)Q描q系l在某个时刻的静态结构; (4) lg?Component Diagram)Q描qC实现pȝ的元素的l织Q? (5) 配置?Deployment Diagram)Q描qC环境元素的配|,q把实现pȝ的元素映到配置上; (6) 状态图(State Diagram)Q描qCpȝ元素的状态条件和响应Q? (7) 时序?Sequence Diagram)Q按旉序描述pȝ元素间的交互Q? (8) 协作?Collaboration Diagram)Q按照时间和I间序描述pȝ元素间的交互和它们之间的关系Q? (9) zd?Activity Diagram)Q描qCpȝ元素的活动; 建模Ҏ?b>建模语言和徏模过E?/b>两部分构成。其中徏模语a是用来表q设计方法的表示法,建模q程是对设计中所应采取的步骤的描q。UML是一U徏模语aQ它在很大程度上独立于徏模过E。在实际建模中,建模人员最好把UML用于以用案驱动的、以体系机构Z心的、P代的和渐增式的开发过E中? 一般而言QY件系l的体系l构l出了Y件系l的l织、组成系l的构造元素及其接口的选择、系l的行ؓ和体pȝ构风格等信息。也是_它不仅关心系l的l构和行为等功能性需求,而且也涉及系l的性能、易理解性、易复用性等非功能性需求。如下图所C,UML利用用户模型视图、结构模型视图、行为模型视图、实现模型视囑֒环境模型视图来描qY件系l的体系l构? Ҏ它们在不同架构视囄应用Q可以把9U图分成Q?/b> (1) 用户模型视图Q用例图Q?/a> (2) l构模型视图Q类囑֒对象Q? (3) 行ؓ模型视图Q状态图、时序图、协作图和活动图Q动态图Q; (4) 实现模型视图Q组件图Q? (5) 环境模型视图Q配|图? 用户模型视图׃门描q?b>最l用戗分析h员和试人员看到的系l行为的用案l成Q它实际上是从用戯?/b>来描q系l应该具有的功能。用h型视图所描述的系l功能依靠外部用h者另外一个系l来Ȁz,为用h者另一pȝ提供服务Q从而实现用h另一pȝ与系l的交互。系l实现的最l目标是提供用户模型视图中所描述的功能。在UML中,用户模型视图是由用案囄?/b>? l构模型视图描述l成pȝ?b>cR对象以及它们之间的关系{静态结构,用来支持pȝ的功能需求,xq系l内部功能是如何设计的。结构模型视囄cd和对象图构成Q?b>主要供设计h员和开发h员?/b>? 行ؓ模型?/b>图主要用来描qŞ?b>pȝq发与同步机制的U程和进E?/b>Q其x的重Ҏpȝ的性能、易伸羃性和pȝ的吞吐量{非功能性需求。行为模型视囑ֈ用ƈ发来描述资源的高效用、ƈ行执行和处理异步事g。除了讲pȝ划分为ƈ发执行的控制U程之外Q行为模型还必须处理通信和这些线E及q程之间的同步问题。行为模型视图主要供pȝ开发h员和pȝ集成人员使用Q它?b>序列图、协作图、状态图和活动图l成? 实现模型视图用来描述pȝ的实现模块它们之间的依赖关系以及资源分配情况。这U视图主要用于系l的配置理Q它是由一些独立的构gl成的。实现模型视囄构g囄?/b>。其中构件是代码模块Q不同类型的代码模块形成不同的构件。实现模型视图主要供开发h?/b>使用? 环境模型视图用来描述物理pȝ?b>g拓扑l构。例如,pȝ中的计算机和讑֤的分布情况以及它们之间的q接方式Q其中计机和设备统UCؓ节点。在UML中环境模型视图是由部|图来表C的。系l部|图描述了系l构件在节点上的分布情况Q即用来描述软g构g到物理节点的映射。部|图主要?b>开发h员、系l集成h员和试人员使用? 上面每一U视囑֏映了pȝ的一个特定方面,不同人员可以单独的用其中每一U视图,从而可以关注特定的体系l构问题。但在通常情况下,׃pȝ的最l目标是提供用户模型视图中描q的功能以及其它一些非功能性需求,因此Q用h型视图是其它视图的核心基Q其它视囄构造都依赖与用h型视图中所描述的类宏V? l心的读者已l发玎ͼ每一UUMLN是由多个囄成的Q每一U图都是体系l构某个侧面的表C,各种囑֮际上是一致的Q所有的囑֜一L成了pȝ的完整视图。如下图所C,UML中d提供了用案图、类图、对象图、序列图、协作图、状态图、活动图、构建图和部|图9U图。根据它们描q的是系l的静态结构还是动态行为,可以它们分为静态图和动态图两类。再q一步介l这9中UML图时Q先了解下什么是模型元素Q? 3. UML的徏模机?/b> UML有两套徏模机Ӟ静态徏模机制和动态徏模机制。静态徏模机制包括用例图、类图、对象图、包、组件图和配|图。动态徏模机制包括状态图、时序图、协作图、活动图? (1) 用例图:用例的可视化工具Q它提供计算机系l的高层ơ的用户视图Q表CZ外部zd者的角度来看pȝ是怎样使用的? 用例图(用案图)是用于描qCl用案,参与者以及它们之间的q接关系。一个用案图描述了一l动作序列,每一个序列表C系l的外部设施Q系l的参与者)与系l本w的交互。从一个特定参与者的角度看,一个用案完成对其有价值的工作。如?.5所C,用案图仅仅是从参与者用系l的角度来描q系l中的信息,即站在系l外部查看系l应该具有什么功能,而ƈ不描q该功能在Y件内部是如何实现的。用案可以应用于整个pȝQ也可以应用于系l的一个部分,包括子系l、单个的cL者接口。通常Q用案不仅代表这些元素所期望的行为,而且q可以把q些元素用作开发过E中试用案的基? 用例囑括以?斚w内容Q? (a) 用例(Use Case) (b) 参与?Actor) (c) 依赖、泛化和兌关系 用例囄例: (2) cdQ描q类、接口、协作以及它们之间关pȝ图? cd是用于描qCl类、接口、协作以及它们之间的静态关pR在面向对象pȝ的徏模中Q类图是最为常用的图,它用来阐明系l的静态结构。事实上cL对一l具有相同属性、操作、关pd语义的对象的描述Q其中对cȝ属性和操作q行描述时的一个最重要的细节就是它的可见性? cd以以多种形式q接Q例如关联、泛化、依赖和实现{。一个典型的pȝ中通常有若q个cd。一个类图不一定要包含pȝ中所有的c,一个类可以加到几个cd中? cdCZQ? (3) 对象图:表示在某一旉上一l对象以及它们之间的关系的图。对象图可以被看做是cd在系l某一时刻的实例? 对象图是cd的实例,用来描述特定q行时刻一l对象之间的关系。也是_对象用于描述交互的静态部分,它由参与协作的有兛_象组成。但不包括在对象之间传递的M消息? 在创建对象图Ӟ建模人员q不需要用单个的对象图来描q系l中的每一个对象。事实上Q绝大多数系l中都会包含成百上千的对象。用对象来描q系l的所有对象以及它们之间的关系一般是不太现实的。因此,建模人员可以选择所感兴的对象极其之间的关pL描述? 对象图中所使用的符号和cd中用的W号几乎完全相同Q区别仅在于对象囄对象名带有下划线Q而且cMcM间关pȝ所有的实例都要d来? (4) lg?/a>Q描qY件组件以及组件之间的关系Q组件本w是代码的物理模块,lg囑ֈ昄了代码的l构? lg图(构g图)是用于描qCl构件之间的l织和依赖关p,用于建模pȝ的静态实现视图。构件可以是可执行程序集、库、表、文件和文档{,它包含了逻辑cL者逻辑cȝ实现信息Q因此结构模型视囑֒实现模型视图之间存在映射关系? 构徏图中也可以包括包或子pȝQ它们都是用于将模型元素l成较大的组块? lg图例图: (5) 配置?/a>Q描q系l硬件的物理拓扑l构以及在此l构上执行的软g。配|图可以昄计算节点的拓扑结构和通信路径、结点上q行的Y件组件、Y件组件包含的逻辑单元Q对象、类Q等。配|图常常用于帮助理解分布式系l? 配置图(部v图)用来描述pȝq行是进行处理的节点以及在节点上zd的构件的配置。部|图用来对系l的环境模型视图q行建模。在大多数情况下Q部|图用来描述pȝg的扩普结构? 在UML中,建模人员可以用类图来描述pȝ的静态结构,可以用序列图、协作图、状态图、活动图来描q系l的动态行为,而用部v图来描述软g所执行所需的处理器和设备的拓扑l构? (6) 状态图Q通过cd象的生命周期建立模型来描q对象随旉变化的动态行为? 状态图实际上是一U由状态、变q、事件和zdl成的状态机。状态图描述从状态到状态的控制,常用于系l的动态特性徏模。在大多数情况下Q它用来对反应型对象的行为徏模? 在UML中,状态图可以用来对一个对象按事g排序的行为徏模。一个状态图是强调从状态到状态的控制的状态机的简单表C。一般而言Q状态图是对cL描述的设施的补充说明Q它描述了类的所有对象可能具有的状态以及引L态变化的事g? (7) 时序图:交互图描qC一个交互,它由一l对象和它们之间的关pȝ成,q且q包括在对象间传递的信息。交互图表达对象之间的交互,是描qCl对象如何协作完成某个行为的模型化工兗? 序列囑֒协作囄UCؓ交互图。其中,序列囄来描q对象之间消息发送的先后ơ序Q阐明对象之间的交互q程以及在系l执行过E中的某一具体时刻会发生什么事件。序列图是一U强调时间顺序的交互图,其中对象沿横轴方向排列,消息沿纵轴方向排列? 序列图中的对象生命线是一条垂直的虚线Q它表示一个对象在一D|间内存在。由于序列图中大多数对象都存在于整个交互q程中,因此q些对象全部排列在图的顶部,它们的生命线从图的顶部画到图的底部。每个对象的下方有一个矩形条Q它与对象的生命UK叠,它表C对象的控制焦炏V序列图中的消息可以有序P但由于这U图上的消息已经从纵轴上按时间顺序排序,因此消息序号通常予以省略? (8) 协作图:包含cd角色和关联角Ԍ而不仅仅是类元和兌。协作图参加交互的各对象的组l。协作图只对怺间有交互作用的对象和q些对象间的关系建模Q而忽略了其他对象和关联。协作图也是一U交互图Q它收发消息的对象的l织l构? 协作囑֒序列图是协作的,它们可以互相转换。在多数情况下,协作图主要对单调的、顺序的控制徏模,但它也可以用来对包括q代和分支在内的复杂控制进行徏模? 一般而言Q徏模h员可以创建多个协作图Q其中一些是主要的,另外一些是可选择的\径或者异常条件。徏模h员可以用包来l织q些协作图,q给每个图v一个合适的名字Q以便与其它囑别开? (9) zd图:用于展现参与行ؓ的类的活动或动作? zd图是状态图的一U特D情况,其中几乎所有或大多数状态都处于zd状态,而且几乎所有或者大多数变迁都是由源状态中zd的完成触发的。活动图本质上是一U流E图Q它描述了从zd到活动的控制? 可以把活动图看作是新L交互图,但交互图观察的是传递消息的对象Q而活动图观察到的是对象之间传送的消息。尽两者在语义上的区别很细微,但它们用不同的方式来看pȝ的? 如果你觉得本文不错的话,请你点击屏幕右下方的 最后,Ƣ迎大家l箋支持和关注我的博客: http://blog.csdn.net/IBM_hoojo 也欢q大家和我交、探讨IT斚w的知识?/p> 在UMLcd中,常见的有以下几种关系: 泛化QGeneralizationQ? 实现QRealizationQ,兌QAssociation)Q聚合(AggregationQ,l合(Composition)Q依?Dependency)? 1.1?l承关系—泛化(GeneralizationQ? 指的是一个类Q称为子cR子接口Q承另外的一个类Q称为父cR父接口Q的功能Qƈ可以增加它自q新功能的能力Q承是cMcL者接口与接口之间最常见的关p;在Java中用extends关键字? 【泛化关pR是一U承关p,表示一般与Ҏ的关p,它指定了子类如何特化父类的所有特征和行ؓ。例如:猫头鹰是鸟的一U,x鸟的Ҏ也有猫头鹰的共性? 【箭头指向】带三角头的实U,头指向父类? 【描q】上图中的类bird有嘴、翅膀、羽毛等属性。会飞、会唧唧喛_的叫Q那么就有这些方法。而猫头鹰有大眼睛和捕捉老鼠的本领,q则是自w的Ҏ?/p> 1.2?实现关系QRealizationQ? 指的是一个classcd现interface接口Q可以是多个Q的功能Q实现是cM接口之间最常见的关p;在Java中此cdp通过关键字implements明确标识? 【实现关pR是一U类与接口的关系Q表C类是接口所有特征和行ؓ的实? 【箭头指向】带三角头的虚U,头指向接口? 【描q】上图中IFly是一个接口,接口中有旉、速度{常量,q有一个flyҎ。FlyImpll承了这个IFly接口后,需要实现flyҎQ同时实现类也可以拥有自q属性和Ҏ?/p> 1.3?依赖QDependencyQ? 可以单的理解Q就是一个类A使用C另一个类BQ而这U用关pLh偶然性的、时性的、非常弱的,但是Bcȝ变化会媄响到AQ比如某q河Q需要借用一条船Q此时h与船之间的关pd是依赖;表现在代码层面,为类B作ؓ参数、属性被cA在某个methodҎ中用; 【依赖关pR是一U用的关系Q即一个类的实现需要另一个类的协助,所以要量不用双向的互相依赖? 【代码表现】局部变量、方法的参数或者对静态方法的调用 【箭头及指向】带头的虚U,指向被用? 【描q】BirdcM有一个setFlyҎQ它需要用者用到IFly接口的实玎ͼ那么q种关系是依赖关系?/p> 1.4?兌 他体现的是两个类、或者类与接口之间语义别的一U强依赖关系Q比如我和我的朋友;q种关系比依赖更强、不存在依赖关系的偶然性、关pM不是临时性的Q一般是长期性的Q而且双方的关pM般是q等的、关联可以是单向、双向的Q表现在代码层面Qؓ被关联类B以类属性的形式出现在关联类A中,也可能是兌cA引用了一个类型ؓ被关联类B的全局变量Q? 【关联关pR是一U拥有的关系Q它使一个类知道另一个类的属性和ҎQ如Q老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的兌可以有两个箭头或者没有箭_单向的关联有一个箭头? 【代码体现】成员变? 【箭头及指向】带普通箭头的实心U,指向被拥有? 【描q】在BirdcM有一个IFlycd的fly属性,需要提供IFly的接口实现。Bird对象会利用IFly接口的实现完成flyҎ?/p> 1.4.1、双向关? 双方都知道对方的存在Q都可以调用Ҏ的公共属性、方法? 【关联关pR双斚w有关联的关系Q通过自n对对方关联的属性来讉KҎ的属性和Ҏ?/a> 【代码体现】成员变? 【箭头及指向】用不带头的实U连接双? 【描q】在中国一个妻子只能嫁l一个丈夫,一个丈夫也只能取一个妻子? 1.4.2、自w关? 自己兌自己Q这U情冉|较少出现但是也有用到? 【自兌关系】双斚w有关联的关系Q通过自n对自w关联的属性引用来讉KҎ的属性和Ҏ? 【代码体现】成员变? 【箭头及指向】用带普通箭头的实线q接自己 【描q】在盗梦I间中,演员需要在梦中再造梦Q这U梦中梦的情况跟上图描述很符合? 1.5?聚合QAggregationQ? 聚合是关联关pȝ一U特例,他体现的是整体与部分、拥有的关系Q即has-a的关p,此时整体与部分之间是可分ȝQ他们可以具有各自的生命周期Q部分可以属于多个整体对象,也可以ؓ多个整体对象׃nQ比如计机与CPU、公怸员工的关pȝQ表现在代码层面Q和兌关系是一致的Q只能从语义U别来区分; 【聚合关pR是整体与部分的关系Q且部分可以d整体而单独存在。如车和轮胎是整体和部分的关p,轮胎d车仍然可以存在。聚合关pL兌关系的一U,是强的关联关p;兌和聚合在语法上无法区分,必须考察具体的逻辑关系? 【代码体现】成员变? 【箭头及指向】带I心菱Ş的实心线Q菱形指向整? 【描q】birdChild一只鸟有很多鸟宝宝Q所以自引用。鸟有很多不同数量和颜色的羽毛,所以引用关pL0~*?/p> 1.6?l合QCompositionQ? l合也是兌关系的一U特例,他体现的是一Ucontains-a的关p,q种关系比聚合更强,也称为强聚合Q他同样体现整体与部分间的关p,但此时整体与部分是不可分的,整体的生命周期结束也意味着部分的生命周期结束;比如你和你的大脑Q表现在代码层面Q和兌关系是一致的Q只能从语义U别来区分; 【组合关pR是整体与部分的关系Q但部分不能d整体而单独存在。如公司和部门是整体和部分的关系Q没有公司就不存在部门。组合关pL兌关系的一U,是比聚合关系q要强的关系Q它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期? 【代码体现】成员变? 【箭头及指向】带实心菱Ş的实U,菱Ş指向整体 【描q】一个学校由多个班l成Q班U离开学校也就不存在、而学校离开班也不成立。像q种不可分离的关pd需要用l合?/p> l合CZ 对于l承、实现这两种关系没多疑问,他们体现的是一U类与类、或者类与接口间的纵向关p;其他的四者关pd体现的是cMcR或者类与接口间的引用、横向关p,是比较难区分的,有很多事物间的关p要惛_备定位是很难的,前面也提刎ͼq几U关p都是语义别的Q所以从代码层面q不能完全区分各U关p;但ȝ来说Q后几种关系所表现的强q度依ơؓQ泛?= 实现 > l合 > 聚合 > 兌 > 依赖?/p> Eclipse下的Java反编译插ӞEclipse Class DecompilerQ整合了目前最好的2个Java反编译工具Jad和JD-CoreQƈ且和Eclipse Class Viewer无缝集成Q能够很方便的用本插g查看cd源码Q以及采用本插gq行Debug调试?/p> 转蝲自:http://bbs.csdn.net/topics/390263414 Eclipse Class Decompiler插gQ?http://download.csdn.net/detail/ibm_hoojo/5250263 下图为Eclipse Class Decompiler的首选项面Q可以选择~省的反~译器工Pq进行反~译器的基本讄。缺省的反编译工具ؓJD-CoreQJD-Core更ؓ先进一些,支持泛型、Enum、注解等JDK1.5以后才有的新语法?br> 插g提供了系l菜单,工具栏,当打开了插件提供的cd~译查看器后Q会Ȁz菜单和工具栏选项Q可以方便的q行首选项配置Q切换反~译工具重新反编译,以及导出反编译结果?br> cd~译查看器右键菜单包含了Eclipse自带cL看器右键菜单的全部选项Qƈ增加了一个“导出反~译源代码”菜单项?br> 打开目路径下的Class文gQ如果设|类反编译查看器为缺省的查看器,直接双击Class文g卛_Q如果没有设|ؓ~省查看器,可以使用右键菜单q行查看?br> Eclipse Class Decompiler插g也提供了反编译整个Jar文g或者Java包的反编译。该操作支持Package Explorer对包昄布局的操作,如果是^铺模式布局Q则导出的源代码不包含子包,如果是层U模式布局Q则导出选中的包及其所有的子包?br> Debug调试Q可以在首选项选中寚w行号q行单步跟踪调试Q和普通的包含源代码时的调试操作完全一_同样的也可以讄断点q行跟踪?br> 转蝲Q?a >http://bbs.csdn.net/topics/390263414 本h是做Java开发的Q在E序开发中会经怋用到OpenSource开源框Ӟq些框架大多都灵zR简单、易用、方ѝ而且开源框架一般会提供一些基本的配置Q如我们常用的框架就有Hibernate要配|对象实体到数据库的映射QSpring要配|bean的管理及其对象、属性的注入QStruts要配|Action对象和返回的资源路径QMyBatis要配|CRUDQ增删改查)的相关SQL语句。这些配|你不能省略Q必d有,没有E序也不会自动添加。我们也是极可能的简化这些配|,不管怎么L化但q些配置是不能省略,虽然q些框架l我们开发程序都提供了很大方面上的便利?/p> 但有时候你是否有纠l这么样的一个问题:到底是用XML配置Q还是用Annotation注解配置Q或是用XML和Annotation混合配置Q?/font> 首先看看两种配置的优~点比较 XML它是无可代替的超文本标记语言Q可L、传输性好Q它q具有一下优点: 让我们来看看Annotation的优?br>1、保存在class文g中,降低l护成本?br>2、无需工具支持Q无需解析?br>3、编译期卛_验证正确性,查错变得ҎQ虽然有部分错误需要在q行期间才能看到?br>4、配|简单、简U,提升开发效率? 那到底用什么样的配|呢Q在q里我谈谈我个h的看法: 如果q样是不是即利用到框架给我们提供的Annotation注解Q也利用CXML配置。充分的发挥了开源框架给我们提供的技术应用? 3、合模式,Annotation和XML怺q用。需要动态配|、后期经常性修改的qXML配置Q如果是不怎么修改的就用Annotation。或许这U合模式更适合我们Q你觉得呢?O(∩_?O~ 全文索是指计机索引E序通过扫描文章中的每一个词Q对每一个词建立一个烦引,指明该词在文章中出现的次数和位置Q当用户查询Ӟ索程序就Ҏ事先建立的烦引进行查找,q将查找的结果反馈给用户的检索方式。这个过E类g通过字典中的索字表查字的q程? 全文索的Ҏ主要分ؓ按字索和按词索两U。按字检索是指对于文章中的每一个字都徏立烦引,索时词分解为字的组合。对于各U不同的语言而言Q字有不同的含义Q比如英文中字与词实际上是合一的,而中文中字与词有很大分别。按词检索指Ҏ章中的词Q即语义单位建立索引Q检索时按词索,q且可以处理同义等。英文等西方文字׃按照I白切分词,因此实现上与按字处理cMQ添加同义处理也很容易。中文等东方文字则需要切分字词,以达到按词烦引的目的Q关于这斚w的问题,是当前全文检索技术尤其是中文全文索技术中的难点,在此不做详述? 全文索系l是按照全文索理论徏立v来的用于提供全文索服务的软gpȝ。一般来_全文索需要具备徏立烦引和提供查询的基本功能,此外C的全文检索系l还需要具有方便的用户接口、面向WWW[1]的开发接口、二ơ应用开发接口等{。功能上Q全文检索系l核心具有徏立烦引、处理查询返回结果集、增加烦引、优化烦引结构等{功能,外围则由各种不同应用h的功能组成。结构上Q全文检索系l核心具有烦引引擎、查询引擎、文本分析引擎、对外接口等{,加上各种外围应用pȝ{等共同构成了全文检索系l。图1.1展示了上q全文检索系l的l构与功能? 在上图中Q我们看刎ͼ全文索系l中最为关键的部分是全文检索引擎,各种应用E序都需要徏立在q个引擎之上。一个全文检索应用的优异E度Q根本上由全文检索引擎来军_。因此提升全文检索引擎的效率x我们提升全文索应用的Ҏ。另一个方面,一个优异的全文索引擎,在做到效率优化的同时Q还需要具有开攄体系l构Q以方便E序员对整个pȝq行优化攚w,或者是d原有pȝ没有的功能。比如在当今多语a处理的环境下Q有旉要给全文索系l添加处理某U语a或者文本格式的功能Q比如在英文pȝ中添加中文处理功能,在纯文本pȝ中添加XML或者HTML格式的文本处理功能,pȝ的开放性和扩充性就十分的重要? Lucene是apache软g基金会jakarta目l的一个子目Q是一个开放源代码的全文检索引擎工具包Q即它不是一个完整的全文索引擎,而是一个全文检索引擎的架构Q提供了完整的查询引擎和索引引擎Q部分文本分析引擎(英文与d文两U西方语aQ。Lucene的目的是Y件开发h员提供一个简单易用的工具包,以方便的在目标系l中实现全文索的功能Q或者是以此为基建立起完整的全文索引擎? Lucene的原作者是Doug CuttingQ他是一位资深全文烦?索专Ӟ曄是V-Twin搜烦引擎的主要开发者,后在Excite担Q高pȝ架构设计师,目前从事于一些Internet底层架构的研I。早先发布在作者自qhttp://www.lucene.com/Q后来发布在SourceForgeQ?001q年底成为apache软g基金会jakarta的一个子目Q?a >http://jakarta.apache.org/lucene/? 作ؓ一个开放源代码目QLucene从问世之后,引发了开放源代码C的巨大反响,E序员们不仅使用它构建具体的全文索应用,而且之集成到各U系lY件中去,以及构徏Web应用Q甚x些商业Y件也采用了Lucene作ؓ其内部全文检索子pȝ的核心。apache软g基金会的|站使用了Lucene作ؓ全文索的引擎QIBM的开源Y件eclipse?.1版本中也采用了Lucene作ؓ帮助子系l的全文索引引擎Q相应的IBM的商业Y件Web Sphere中也采用了Lucene。Lucene以其开放源代码的特性、优异的索引l构、良好的pȝ架构获得了越来越多的应用? Lucene作ؓ一个全文检索引擎,其具有如下突出的优点Q? Q?Q烦引文件格式独立于应用q_。Lucene定义了一套以8位字节ؓ基础的烦引文件格式,使得兼容pȝ或者不同^台的应用能够׃n建立的烦引文件? Q?Q在传统全文索引擎的倒排索引的基上,实现了分块烦引,能够针对新的文g建立文件烦引,提升索引速度。然后通过与原有烦引的合ƈQ达C化的目的? Q?Q优U的面向对象的pȝ架构Q得对于Lucene扩展的学习难度降低,方便扩充新功能? Q?Q设计了独立于语a和文件格式的文本分析接口Q烦引器通过接受Token完成烦引文件的创立Q用h展新的语a和文件格式,只需要实现文本分析的接口? Q?Q已l默认实C一套强大的查询引擎Q用h需自己~写代码即ɾpȝ可获得强大的查询能力QLucene的查询实C默认实现了布操作、模p查询(Fuzzy SearchQ、分l查询等{? 面对已经存在的商业全文检索引擎,Lucene也具有相当的优势Q? 首先Q它的开发源代码发行方式Q遵守Apache Software LicenseQ,在此基础上程序员不仅仅可以充分的利用Lucene所提供的强大功能,而且可以深入l致的学习到全文索引擎制作技术和面相对象~程的实践,q而在此基上根据应用的实际情况~写出更好的更适合当前应用的全文检索引擎。在q一点上Q商业Y件的灉|性远q不及Lucene。其ơ,LuceneU承了开放源代码一贯的架构优良的优势,设计了一个合理而极h充能力的面向对象架构Q程序员可以在Lucene的基上扩充各U功能,比如扩充中文处理能力Q从文本扩充到HTML、PDF{等文本格式的处理,~写q些扩展的功能不仅仅不复杂,而且׃Lucene恰当合理的对pȝ讑֤做了E序上的抽象Q扩展的功能也能L的达到跨q_的能力。最后,转移到apache软g基金会后Q借助于apache软g基金会的|络q_Q程序员可以方便的和开发者、其它程序员交流Q促成资源的׃nQ甚至直接获得已l编写完备的扩充功能。最后,虽然Lucene使用Java语言写成Q但是开放源代码C的程序员正在不懈的将之用各U传l语a实现Q例?net frameworkQ,在遵守Lucene索引文g格式的基上,使得Lucene能够q行在各U各Lq_上,pȝ理员可以根据当前的q_适合的语a来合理的选? Lucene作ؓ一个优U的全文检索引擎,其系l结构具有强烈的面向对象特征。首先是定义了一个与q_无关的烦引文件格式,其次通过抽象系l的核心l成部分设计为抽象类Q具体的q_实现部分设计为抽象类的实玎ͼ此外与具体^台相关的部分比如文g存储也封装ؓc,l过层层的面向对象式的处理,最l达成了一个低耦合高效率,Ҏ二次开发的索引擎系l? 以下讨论Lucenepȝ的结构组l,q给出系l结构与源码l织图: 从图中我们清楚的看到QLucene的系l由基础l构装、烦引核心、对外接口三大部分组成。其中直接操作烦引文件的索引核心又是pȝ的重炏VLucene的将所有源码分Z7个模块(在java语言中以包即package来表C)Q各个模块所属的pȝ部分也如上图所C。需要说明的是org.apache.lucene.queryPaser是做为org.apache.lucene.search的语法解析器存在Q不被系l之外实际调用,因此q里没有当作对外接口看待Q而是之独立出来? 从面象对象的观点来考察QLucene应用了最基本的一条程序设计准则:引入额外的抽象层以降低耦合性。首先,引入对烦引文件的操作org.apache.lucene.store的封装,然后烦引部分的实现建立在(org.apache.lucene.indexQ其之上Q完成对索引核心的抽象。在索引核心的基上开始设计对外的接口org.apache.lucene.search与org.apache.lucene.analysis。在每一个局部细节上Q比如某些常用的数据l构与算法上QLucene也充分的应用了这一条准则。在高度的面向对象理论的支撑下,使得Lucene的实现容易理解,易于扩展? Lucene在系l结构上的另一个特点表Cؓ其引入了传统的客L服务器结构以外的的应用结构。Lucene可以作ؓ一个运行库被包含进入应用本w中去,而不是做Z个单独的索引服务器存在。这自然和Lucene开放源代码的特征分不开Q但是也体现了Lucene在编写上的本来意图:提供一个全文烦引引擎的架构Q而不是实现? 了解数据分析的重要性: 理解Lucenepȝl构的另一个方式是L讨其中数据流的走向,q以此摸清楚Lucenepȝ内部的调用时序。在此基上,我们能够更加深入的理解Lucene的系l结构组l,以方便以后在Lucenepȝ上的开发工作。这部分的分析,是深入Lucenepȝ的钥匙,也是q行重写的基? Lucenepȝ中的主要的数据流以及它们之间的关pdQ? ?.2很好的表明了Lucene在内部的数据组l情况,q且沿着数据的方向我们也可以对与Lucene内部的执行时序有一个清楚的了解。现在将图中的涉及到的流的类型与各个逻辑对应pȝ的相关部分的关系说明一下? 图中共存?U数据流Q分别是文本、token、字节流与查询语句对象流。文本流表示了对于烦引目标和交互控制的抽象,即用文本表CZ要索引的文Ӟ用文本流向用戯Z息;在实际的实现中,Lucene中的文本采用了UCS-2作ؓ~码Q以辑ֈ适应多种语言文字的处理的目的。Token是Lucene内部所使用的概念,是对传统文字中的词的概念的抽象,也是Lucene在徏立烦引时直接处理的最单位;单的讲Token是一个词和所在域值的l合Q后面在叙述文g格式时也l涉及到tokenQ这里不详细展开。字节流则是Ҏ件抽象的直接操作的体玎ͼ通过固定长度的字节(Lucene定义?比特位长Q后面文件格式将详细叙述Q流的处理,文件操作解脱出来,也做C与^台文件系l的无关性。查询语句对象流则是仅仅在查询语句解析时用到的概念,它对查询语句抽象Q通过cȝl承l构反映查询语句的结构,之传送到查找逻辑来进行查扄操作? 图中的涉及到了多U逻辑Q基本上直接对应于系l某一模块Q但是也有跨模块调用的问题发生,q是因ؓLucene的重用程度非常好Q因此很多实现直接调用了以前的工作成果,q在某种E度上其实是加强了模块耦合性,但是也是Z避免pȝ的过于庞大和不必要的重复设计的一U折衷体现。词法分析逻辑对应于org.apache.lucene.analysis部分。查询语句语法分析逻辑对应于org.apache.lucene.queryParser部分Qƈ且调用了org.apache.lucene.analysis的代码。查询结束之后向评分排序逻辑输出token,l而由评分排序逻辑处理之后l出文本的l果Q这一部分的实C包含在了org.apache.lucene.search中。烦引构建逻辑对应于org.apache.lucene.index部分。烦引查N辑则主要是org.apache.lucene.searchQ但是也大量的用了org.apache.lucene.index部分的代码和接口定义。存储抽象对应于org.apache.lucene.store。没有提到的模块则是做ؓpȝ公共基础设施存在? 首先Q我们需要的是按照目标语a的词法结构来构徏相应的词法分析逻辑Q实现Lucene在org.apache.lucene.analysis中定义的接口QؓLucene提供目标pȝ所使用的语a处理能力。Lucene默认的已l实C英文和d文的单词法分析逻辑Q按照空格分词,q去除常用的语法词,如英语中的isQamQare{等Q。在q里Q主要需要参考实现的接口在org.apache.lucene.analysis中的Analyzer.java和Tokenizer.java中定义,Lucene提供了很多英文规范的实现hQ也可以做ؓ实现时候的参考资料。其ơ,需要按照被索引的文件的格式来提供相应的文本分析逻辑Q这里是指除开词法分析之外的部分,比如HTML文gQ通常需要把其中的内Ҏ照所属于域分门别cd入烦引,q就需要从org.apache.lucene.document中定义的cdocumentl承Q定义自qHTMLDocumentc,然后可以将之交lorg.apache.lucene.index模块来写入烦引文件。完成了q两步之后,Lucene全文索引擎就基本上完备了。这个过E可以用下图表示Q? 下面是用java语言开发,Lucenepȝ能够方便的嵌入到整个pȝ中去Q作Z个API集来调用。这个过E十分简单,以下便是一个示例程序,配合注释理解h很容易? 首先在Lucene的文件格式中Q以字节为基Q定义了如下的数据类型: ?/b> 3.1 Lucene文g格式中定义的数据cd 数据cd 所占字节长度(字节Q?/b> 说明 Byte 1 基本数据cdQ其他数据类型以此ؓ基础定义 UInt32 4 32位无W号整数Q高位优?/p> UInt64 8 64位无W号整数Q高位优?/p> VInt 不定Q最?字节 动态长度整敎ͼ每字节的最高位表明q剩多少字节Q每字节的低七位表明整数的|高位优先。可以认为值可以ؓ无限大。其CZ如下 ?/p> 字节1 字节2 字节3 0 00000000 1 00000001 2 00000010 127 01111111 128 10000000 00000001 129 10000001 00000001 130 10000010 00000001 16383 10000000 10000000 00000001 16384 10000001 10000000 00000001 16385 10000010 10000000 00000001 Chars 不定Q最?字节 采用UTF-8~码[20]的Unicode字符序列 String 不定Q最?字节 由VInt和Charsl成的字W串cdQVInt表示Chars的长度,Chars则表CZString的?/p> 以上的数据类型就是Lucene索引文g格式中用到的全部数据cdQ由于它们都以字节ؓ基础定义而来Q因此保证了是^台无养Iq也是Lucene索引文g格式q_无关的主要原因。接下来我们看看Lucene索引文g的概늻成和l构l成? 以上是Lucene的烦引文件的概念l构。Lucene索引indexpq段(segment)l成Q每一D는若干的文档(documentQ组成,每一个文档由若干的域QfieldQ组成,每一个域pq的(termQ组成。项是最的索引概念单位Q它直接代表了一个字W串以及其在文g中的位置、出现次数等信息。域是一个关联的元组Q由一个域名和一个域值组成,域名是一个字Ԍ域值是一个项Q比如将“标题”和实际标题的项l成的域。文档是提取了某个文件中的所有信息之后的l果Q这些组成了D,或者称Z个子索引。子索引可以l合为烦引,也可以合qؓ一个新的包含了所有合q内部元素的子索引。我们可以清楚的看出QLucene的烦引结构在概念上即Zl的倒排索引l构? 从概念上映射到结构中Q烦引被处理Z个目录(文g夹)Q其中含有的所有文件即为其内容Q这些文件按照所属的D不同分l存放,同组的文件拥有相同的文g名,不同的扩展名。此外还有三个文Ӟ分别用来保存所有的D늚记录、保存已删除文g的记录和控制d的同步,它们分别是segmentsQdeletable和lock文gQ都没有扩展名。每个段包含一l文Ӟ它们的文件扩展名不同Q但是文件名均ؓ记录在文件segments中段的名字。让我们看如下的l构?.2Q? 每个D늚文g中,主要记录了两大类的信息:域集合与w合。这两个集合中所含有的文件在?.2中均有表明。由于烦引信息是静态存储的Q域集合与项集合中的文gl采用了一U类似的存储办法Q一个小型的索引文gQ运行时载入内存Q一个对应于索引文g的实际信息文Ӟ可以按照索引中指C的偏移量随问;索引文g与信息文件在记录的排列顺序上存在隐式的对应关p,即烦引文件中按照“烦引项1、烦引项2…”排列,则信息文件则也按照“信息项1、信息项2…”排列。比如在?.2所C文件中Qsegment1.fdx与segment1.fdt之间Qsegment1.tii与segment1.tis、segment1.prx、segment1.frq之间Q都存在q样的组l关pR而域集合与项集合之间则通过域的在域记录文gQ比如segment1.fnmQ中所记录的域记录L持对应关p,在图3.2中segment1.fdx与segment1.tii中就是通过q种方式保持联系。这P域集合和w合不仅仅联系hQ而且其中的文件之间也怺联系h。此外,标准化因子文件和被删除文档文件则提供了一些程序内部的辅助设施Q标准化因子用在评分排序机制中,被删除文档是一U伪删除手段Q。这P整个D늚索引信息通过q些文档有机的组成? 基础l构装Q或者基c,由org.apache.lucene.util和org.apache.lucene.document两个包组成,前者定义了一些常量和优化q的常用的数据结构和法Q后者则是对于文档(documentQ和域(fieldQ概늚一个类定义。以下我们用列表的方式来分析q些装c,指出其要点; ?/b> 3.2 基础cdorg.apache.lucene.util c?/b> 说明 Arrays 一个关于数l的排序Ҏ的静态类Q提供了优化的基于快排序的排序方法sort BitVector C/C++语言中位域的java实现品,但是加入了序列化能力 Constants 帔R静态类Q定义了一些常?/p> PriorityQueue 一个优先队列的抽象c,用于后面实现各种具体的优先队列,提供常数旉内的最元素访问能力,内部实现机制是哈析表和堆排序法 ?/b> 3.3 基础cdorg.apache.lucene.document c?/b> 说明 Document 是文档概늚一个实现类Q每个文档包含了一个域表(fieldListQ,q提供了一些实用的ҎQ比如多U添加域的方法、返回域表的q代器的Ҏ Field 是域概念的一个实现类Q每个域包含了一个域名和一个|以及一些相关的属?/p> DateField 提供了一些辅助方法的静态类Q这些方法将java中Date和Time数据cd和String怺转化
。如果你以后会用到这文章的或觉得以后要重新阅的话Q你可以点击屏幕右下角的
。如果你觉得我的博文不错或是惛_W一旉看到我的动态的话,你可以点dq右下角
。如果你惌点什么的话,你可以点dq右下方?a >
。如果你都点q了Q那真的太谢谢你了,兄弟太支持了。此Ӟ或许你可以点?a >
按钮Q然后看看博文的Dl箋览其他文章?/p>
。如果你以后会用到这文章的或觉得以后要重新阅的话Q你可以点击屏幕右下角的
。如果你觉得我的博文不错或是惛_W一旉看到我的动态的话,你可以点dq右下角
。如果你惌点什么的话,你可以点dq右下方?a >
。如果你都点q了Q那真的太谢谢你了,兄弟太支持了。此Ӟ或许你可以点?a >
按钮Q然后看看博文的Dl箋览其他文章?/p>
]]>
]]>
]]>
]]>
下蝲后,解压可以看到如下目录Q复制所有文件粘贴到你的eclipse或MyEclipse的目录:D:\MyEclipse 6.5\myeclipse\eclipse下,选择覆盖卛_。然后重新启动eclipse?br>
首选项配置选项Q?br>1.重用~存代码Q只会反~译一ơ,以后每次打开该类文gQ都昄的是~存的反~译代码?br>2.忽略已存在的源代码:若未选中Q则查看Class文g是否已绑定了Java源代码,如果已绑定,则显CJava源代码,如果未绑定,则反~译Class文g。若选中此项Q则忽略已绑定的Java源代码,昄反编译结果?br>3.昄反编译器报告Q显C反~译器反~译后生成的数据报告及异怿息?br>4.使用Eclipse代码格式化工P使用Eclipse格式化工具对反编译结果重新格式化排版Q反~译整个Jar包时Q此操作会消耗一些时间?br>5.使用Eclipse成员排序Q用Eclipse成员排序对反~译l果重新格式化排版,反编译整个Jar包时Q此操作会消耗大量时间?br>6.以注释方式输出原始行号信息:如果Class文g包含原始行号信息Q则会将行号信息以注释的方式打印到反~译l果中?br>7.Ҏ行号寚w源代码以便于调试Q若选中该项Q插件会采用AST工具分析反编译结果,q根据行号信息调整代码顺序,以便于Debugq程中的单步跟踪调试?br>8.讄cd~译查看器作为缺省的cL件编辑器Q默认ؓ选中Q将忽略Eclipse自带的Class ViewerQ每ơEclipse启动后,默认使用本插件提供的cL看器打开Class文g?/p>
]]>
]]>
1、可L、传输性好QXML可扩展标记语aQ最大的优势在于开发者能够ؓ软g量n定制适用的标讎ͼ使代码可L大大提升?br>2、灵zL、易用性、扩展性、移植性好Q利用XML配置能软g更具扩展性。如Springclass间的依赖配置在XML中,最大限度地提升应用的可扩展性。同P如果是基于接口注入方式,可以随便切换接口实现c进行注入即可?br>3、验证机Ӟh成熟的验证机制确保程序正性。利用Schema或DTD可以对XML的正性进行验证,避免了非法的配置D应用E序出错?br>4、修攚w|而无需变动现有E序、无需重新~译?
虽然XML有如此多的好处,但它也不是万能的QXML也有自n的缺点:1、开发友好性支持:需要解析工hcd的支持。如果你的XML配置需要用到XML的提C或是解析编译,需要用到Schema或DTDq行验证?br>2、性能影响Q解析XML势必会媄响应用程序性能Q占用系l资源。至你会用C些解析XML的技术去解析节点元素内容?br>3、维护性高Q配|文件过多导致管理变得困难?br>4、编译期无法对其配置的正确性进行验证,或要查错只能在运行期。如Spring Bean配置了一个错误的c\径class?br>5、IDE 无法验证配置的正确性无能ؓ力。如Spring注入一个错误的对象或属性?br>6、查错变得困难。往往配置的一个手误导致莫名其妙的错误?br>7、开发h员不得不同时l护代码和配|文Ӟ开发效率变得低下?br>8、配|项与代码间存在潜规则,改变了Q何一斚w有可能媄响另外一斏V?
同样Annotation也不是万能的Q它也有很多~点1、若要对配置进行修改,不得不修改Java文gQ重新编译打包应用?br>2、配|项~码在Java文g中,可扩展性差、移植性性低?
1、在开发期间我们用Annotation注解Q这样在一定程度上不仅可以省去对XML配置文g的维护,而且大大的提高了开发效率,~短了开发周期?br>2、开发后期,目功能完成Q我们可以将Annotation配置转换为XML配置Q禁用Annotation卛_。这样做的理由是如果目上线Q我们需要修改相关代码的配置Q直接改XML、properties配置文g卛_。这样就不需要开发h员找到相应的代码修改源代码、重新编译打包发布。而xml的配|是可以直接修改的,不需要重新编译,只需重启下你的服务器卛_?
]]>1.1 什么是全文索与全文索系l?/h4>
1.2 什么是Lucene
1.3 Lucene的应用、特点及优势
2. Lucenepȝl构分析
2.1 pȝl构l织
2.2 数据分?/h4>
2.3 ZLucene的应用开?/h4>
2.4 Lucene索引文g格式
2.5 一些公用的基础c?/h4>
org.apache.lucene.store包:存储抽象是唯一能够直接对烦引文件存取的包,因此其主要目的是抽象出和q_文gpȝ无关的存储抽象,提供诸如目录服务Q增、删文gQ、输入流和输出流。在分析其实C前,首先我们看一下UML图;
?/b> 3.3 存储抽象实现UML图(一Q?/b>
?/b> 3.4 存储抽象实现UML图(二)
?/b> 3.4 存储抽象实现UML图(三)
?.2?.4展示了整个org.apache.lucene.store中主要的l承体系。共有三个抽象类定义QDirectory、InputStream和OutputStremQ构成了一个完整的Z抽象文gpȝ的存取体pȝ构,在此基础上,实作Z两个实现品:QFSDirectoryQFSInputStreamQFSOutputStreamQ和QRAMDirectoryQRAMInputStream和RAMOutputStreamQ。前者是以实际的文gpȝ做ؓ基础实现的,后者则是徏立在内存中的虚拟文gpȝ。前者主要用来永久的保存索引文gQ后者的作用则在于烦引操作时是在内存中徏立小的烦引,然后一ơ性的输出合ƈ到文件中去,q一Ҏ们在后面的烦引逻辑部分能够看到。此外,q定以了org.apache.lucene.store.lock和org.apache.lucene.store.with两个辅助内部实现的类用在实现DirectoryҎ的makeLock的时候,以在锁定索引d之前来让客户E序做一些准备工作?
QFSDirectoryQFSInputStreamQFSOutputStreamQ的内部实现依托于java语言中的iocdQ只是简单的做了一个外部逻辑的包装。这当然要归功于java语言所提供的跨q_Ҏ,同时也带了一些隐患:文g存取的效率提升需要依耐于文gcd的优化。如果需要l优化文件存取的效率Q应该还提供一个文件与目录的抽象,以根据各U文件系l或者文件类型来提供一个优化的Z。当Ӟq是应用开发者所不需要关pȝ问题?
QRAMDirectoryQRAMInputStream和RAMOutputStreamQ的内部实现比较直接了Q直接采用了虚拟的文件RAMFilec(定义于文件RAMDirectory.java中)来表C文Ӟ目录则看作一个String与RAMFile对应的关联数l。RAMFile中采用数l来表示文g的存储空间。在此的基础上,完成各项操作的实玎ͼŞ成了Z内存的虚拟文件系l。因为在实际使用Ӟq不会牵涉到很大字节数量的文Ӟ因此q种设计是简单直接的Q也是高效率的?
1Q?(TermQ?/b>
(TermQ:包括概念所实际涉及的类、永久化cR项QTermQ所表示的是一个字W串Q它拥有域、频数和位置信息{等属性。因此,Lucene中设计了两个cL表示q个概念Q如下图
?/b> 4.1 UML图(Q)
上图中,有意的突ZcTerm和TermInfo中的数据成员Q因为它反映了对于项QTermQ这个概늚具体表示。同时上图中也同时列Z用于怹化项QTermQ的代理cTermInfosWriter和TermInfosReaderQ它们完成永久化的功能,需要注意的是,TermInfosReader内部使用了数lindexTerms和indexInfos来存储一pd;而TermInfosWriter则是一个类g链表的结构,通过一个other指向下一个TermInfosWriterQ每一个TermInfosWriter只负责本w那个lastTerm和lastTi的永久化工作。这是一个设计上的技巧,通过扚wdQ或者称为缓冲的方式Q来获得d时候的效率优化Q而通过一个链表式的、各负其责的方式Q来获得写出时候的设计化?
(termQ这部分的设计中Q还有一些重要的接口和类Q?
?4.2 UML图(二)
?.2中,我们看到三个c:TermEnum、TermDocs与TermPositionsQ第一个是抽象c,后两个都是接口。TermEnum的设计主要用在后面Segment和Document{等的实CQ以提供枚D其中每一个项QTermQ的能力。TermDocs是一个接口,用来l承以提供返?lt;document, frequency>值对的能力,通过q个接口可以获得某个项QTermQ在某个文档中出现的频数。TermPositions则是在TermDocs上的扩展Q将(TermQ在文档中的位置信息也表C出来。TermDocsQTermPositionsQ接口的使用方式cM于java中的Enumration接口Q即通过nextҎ跌{Q通过docQfreq{方法获得当前的属性倹{?
2Q?域(FieldQ?/b>
׃Field的基本概念在org.apache.lucene.document中已l做了定义,因此在这部分主要是针寚w文gQ?fnm文g?fdx文g?fdt文gQ所需要的信息再来设计一些类?
?4.3 UML图(三)
?4.3中展C的Q就是表CZ域(FieldQ所兌的属性信息的cR其中isIndexed表示的这个域的值是否被索引q,卛_是否被分词然后索引Q另外两个属性所表示的意思则很明显:一个是域的名字Q一个是域的~号?
关于域表和存取逻辑的UML图:
FieldInfos即ؓ域表的概念表C,内部采用了冗余的方式以获取在通过域的~号讉K或者通过域的名字来访问时候的高效率。FieldsReader与FieldsWriter则分别是写出和读入的代理cR在功能和实CQ这两个c都比较单?
3Q?文档QdocumentQ?/b>
文档QdocumentQ同样也是在org.apache.lucene.document中定义过的结构。由于对于这部分比较重要Q我们也来看看其UML图:
?4.5 UML图(五)
在图4.5中我们看刎ͼDocument的设计基本上沿用了链表的处理Ҏ。左边的DocumentcMZ个数据外包类Q用来提供对于内部结构DocumentFieldList的增加删除访问操作等{。DocumentFieldList才是实际上的数据存储单位Q它用了链表的处理方法,直接指向一个当前的Field对象和下一个DocumentFieldList对象Q这个与前面的类伹{ؓ了能够逐个讉K链表中的节点Q还设计了DocumentFieldEnumeration枚DcR?
?4.6 UML图(六)
实际上定义于org.apache.lucene.index中的有关于Document的就是永久化的代理类。在?.6中给Z其UML图。需要说明的是ؓ什么没有出现读入的ҎQ这个方法已l隐含在?.5中DocumentcM的addҎ中了Q结合图2.4中的E序代码D,我们p够清楚的理解q种设计?
4Q?D(segmentQ?/b>
D(SegmentQ这一部分设计的比较特D,在实现简单的对象l构之上Q还Ҏ的设计了用于D之间合q的cR接下来Q我们仍焉取对照UML分析的方式逐个叙述。接下来我们看Lucene中如何表C段q个概念?
?4.7 UML图(七)
Lucene定义了一个类SegmentInfo用来表示每一个段QSegmentQ的信息Q包括名字(nameQ、含有的文档的数目(docCountQ和D|位于的目录的位置QdirQ。根据烦引文件中的段的意义,有了q三点,p唯一定一个段了。SegmentInfosq个cd是用来表CZ个段的链表(从标准的java.util.Vectorl承而来Q,实际上,也就是烦引(indexQ的意思了。需要注意的是,q里q没有在SegmentInfo中安插一个文档(documentQ的链表。这样做的原因牵涉到Lucene内部对于文档Q相当于一个被索引文gQ的处理QLucene内部采用了赋予文档编Pl域赋值的方式来处理文档,卛_入的文档次~号Q以后用文档可C文档,而\径信息,文g名字{等在以后烦引查N要的属性,都作为域存储下来Q因此SegmentInfo中ƈ没有另外存储一个文档(documentQ的链表Q对于这些的写出和读入,则交l了怹化的代理cL做?
?4.8 UML图(八)
?.8l出了负责段QsegmentQ的d操作的代理类Q而负责段QsegmentQ的写出操作也同h有定义,q些操作都直接实现在了类IndexWritercM。段的操作同样采用了之前的数l或者说是缓冲的处理方式?
针对前面(termQ那部分定义的几个接口,D(segmentQ这部分也需要做相应的接口实玎ͼ因ؓ提供直接遍历讉KD中的各个项的能力对于检索来_无疑是十分重要的。即q部分的设计Q实际上都是在ؓ了检索在服务?
?4.9 UML图(九)
?4.10 UML图(十)
?.9和图4.10分别展示了前面项QtermQ那里定义的接口是如何在q里通过l承实现的。Lucene在处理这部分的时候,也是分成两部分(Segment与Segments开头的c)来实玎ͼ而且很合理的q用了数l的技法,以及注意了扉K用。但是细化到局部,l归是比较简单的按照语义来获得结果而已了?
LuceneZ兼顾建立索引时的效率和读取烦引查扄速度Q引入了分小D徏立烦引的方式Q即每一ơ批量徏立烦引时Q先在内存中的虚拟文件系l中为每一个文档单独徏立一个段Q然后在输出的时候将q些D合q之后输出成为烦引文Ӟq时仅仅存在一个段。多ơ徏立的索引后,如果想优化烦引文Ӟ也可采取合ƈD늚ҎQ将索引中的D合q成Z个段。我们来看一下在IndexWritercM相应的方法的实现Q来了解一下这中徏立烦引的实现?
在mergeSegments函数中,用到几个重要的cȝ构,它们记录了合q时候的一些重要信息,完成合ƈ时候的工作。接下来Q我们来看这几个cȝUML图:
?4.12 UML图(十一Q?/b>
从图4.12中,我们看到Lucene设计一个类SegmentMergeInfo用来保存每一个被合ƈ的段的信息,也保存能够访问其内部的接口句柄,也就是说合ƈ时的操作使用q个cM为对被合q的D늚操作代理。类SegmentMergeQueue则设计ؓorg.apache.lucene.util.PriorityQueue的子c,做ؓSegmentMergeInfo的容器类Q而且附带能够自动排序。SegmentMerger是主要进行操作的c,主要完成合ƈ各个数据的问题?
5Q?IndexReadercMIndexWirterc?/b>
最后剩下的Q就是整个烦引逻辑部分的用接口类了。外界通过q两个类以及文档QdocumentQ类的构造函数调用之Q比如图2.4中的代码CZ所C。下面我们来看一下这部分最后两个类的UML图:
?4.13 UML图(十二Q?/b>
IndexWriter的设计与IndexReader的设计很不相同,前者是一个实现类Q而后者是一个抽象类Q带有没有实现的接口。IndexWriter的主要作用就是接收新加入的文档(documentQ,然后在内部ؓ之生成相应的段Q最后再合ƈq向索引文g中输出,?.11中已l给Z一些实现的代码。由于Lucene在面向对象上装的努力,通过各个构造函数就已经完成了对于各个概늚构造过E,剩下部分的代码主要是依据各个数组或者是链表中的信息Q逐个逐个的将信息写出到相应的文g中去了。IndexReader部分则只是做了接口设计,没有具体的实玎ͼq个和本部分所完成的主要功能有养I索引构徏逻辑。设计这个抽象类的目的是Q预先完成一些函敎ͼZ后的索(searchQ部分的各种形式的IndexReader铺^道\Q也是利用了在同一个包内可以方便访问其它类的保护变量这个java语言的限制?a name="_Toc43005336">
3.2 数据逻辑
从宏观上明白一个系l的设计Q理清楚其中的运行规律,最好的方式应该是通过数据图。在分析了各个位于烦引构建逻辑部分的类的设计之后,我们接下来就通过分析数据图的方式来ȝ一下。但是由于之前提到的原因Q烦引读入部分在q一部分q没有完全实玎ͼ所以我们在数据图中主要给出的是烦引构建的数据图?
对于?.14中所描述的内容,l合Lucene源代码中的一些文件看Q能够加q解。准备阶D可以参考demo文g夹中的org.apache.lucene.demo.IndexFilescdjava文g夹中的org.apache.lucene.document文g包。烦引构建阶D늚主要源码位于java文g夹中org.apache.lucene.index.IndexWriterc,因此q部分可以结合这个类的实现来看。至于内存文件系l,比较复杂Q但是这时的逻辑相对单,因此也不隄解?
上面的数据流囑֍分清楚的勄除了整个索引构徏逻辑q部分的设计Q通过层层嵌套的类l构Q在构徏时候即分步骤有计划的生成了索引l构Q将之存储到内存中的文gpȝ中,然后通过对内存中的文件系l优化合q输出到实际的文件系l中?
本文是在?010q学习Lucene的时候在互联|上摘抄整理而来Q当时是在一家电子商务公司做商品索需要用到LuceneQ所以就研究了下。这文章也是在当时在网l上阅读Lucene相关知识整理而来的?/p>
全文索是指计机索引E序通过扫描文章中的每一个词Q对每一个词建立一个烦引,指明该词在文章中出现的次数和位置Q当用户查询Ӟ索程序就Ҏ事先建立的烦引进行查找,q将查找的结果反馈给用户的检索方式。这个过E类g通过字典中的索字表查字的q程?
全文索的Ҏ主要分ؓ按字索和按词索两U。按字检索是指对于文章中的每一个字都徏立烦引,索时词分解为字的组合。对于各U不同的语言而言Q字有不同的含义Q比如英文中字与词实际上是合一的,而中文中字与词有很大分别。按词检索指Ҏ章中的词Q即语义单位建立索引Q检索时按词索,q且可以处理同义等?
全文索系l是按照全文索理论徏立v来的用于提供全文索服务的软gpȝ。一般来_全文索需要具备徏立烦引和提供查询的基本功能,此外C的全文检索系l还需要具有方便的用户接口、面向WWW[1]的开发接口、二ơ应用开发接口等{。功能上Q全文检索系l核心具有徏立烦引、处理查询返回结果集、增加烦引、优化烦引结构等{功能,外围则由各种不同应用h的功能组成。结构上Q全文检索系l核心具有烦引引擎、查询引擎、文本分析引擎、对外接口等{,加上各种外围应用pȝ{等共同构成了全文检索系l?/p>
什么是LuceneQ?/b> Lucene是apache软g基金会jakarta目l的一个子目Q是一个开放源代码的全文检索引擎工具包Q即它不是一个完整的全文索引擎,而是一个全文检索引擎的架构Q提供了完整的查询引擎和索引引擎Q部分文本分析引擎(英文与d文两U西方语aQ。Lucene的目的是Y件开发h员提供一个简单易用的工具包,以方便的在目标系l中实现全文索的功能Q或者是以此为基建立起完整的全文索引擎? Lucene的原作者是Doug CuttingQ他是一位资深全文烦?索专Ӟ曄是V-Twin搜烦引擎的主要开发者,后在Excite担Q高pȝ架构设计师,目前从事于一些Internet底层架构的研I。早先发布在作者自qhttp://www.lucene.com/Q后来发布在SourceForgeQ?001q年底成为apache软g基金会jakarta的一个子目Q?a >http://jakarta.apache.org/lucene/?/p>
Lucene作ؓ一个全文检索引擎,其具有如下突出的优点Q?/b> Q?Q烦引文件格式独立于应用q_。Lucene定义了一套以8位字节ؓ基础的烦引文件格式,使得兼容pȝ或者不同^台的应用能够׃n建立的烦引文件? Q?Q在传统全文索引擎的倒排索引的基上,实现了分块烦引,能够针对新的文g建立文件烦引,提升索引速度。然后通过与原有烦引的合ƈQ达C化的目的? Q?Q优U的面向对象的pȝ架构Q得对于Lucene扩展的学习难度降低,方便扩充新功能? Q?Q设计了独立于语a和文件格式的文本分析接口Q烦引器通过接受Token完成烦引文件的创立Q用h展新的语a和文件格式,只需要实现文本分析的接口? Q?Q已l默认实C一套强大的查询引擎Q用h需自己~写代码即ɾpȝ可获得强大的查询能力QLucene的查询实C默认实现了布操作、模p查询(Fuzzy SearchQ、分l查询等{?/p>
面对已经存在的商业全文检索引擎,Lucene也具有相当的优势Q?/b> 首先Q它的开发源代码发行方式Q遵守Apache Software LicenseQ,在此基础上程序员不仅仅可以充分的利用Lucene所提供的强大功能,而且可以深入l致的学习到全文索引擎制作技术和面相对象~程的实践,q而在此基上根据应用的实际情况~写出更好的更适合当前应用的全文检索引擎。在q一点上Q商业Y件的灉|性远q不及Lucene? 其次QLuceneU承了开放源代码一贯的架构优良的优势,设计了一个合理而极h充能力的面向对象架构Q程序员可以在Lucene的基上扩充各U功能,比如扩充中文处理能力Q从文本扩充到HTML、PDF{等文本格式的处理,~写q些扩展的功能不仅仅不复杂,而且׃Lucene恰当合理的对pȝ讑֤做了E序上的抽象Q扩展的功能也能L的达到跨q_的能力? 最后,转移到apache软g基金会后Q借助于apache软g基金会的|络q_Q程序员可以方便的和开发者、其它程序员交流Q促成资源的׃nQ甚至直接获得已l编写完备的扩充功能。最后,虽然Lucene使用Java语言写成Q但是开放源代码C的程序员正在不懈的将之用各U传l语a实现Q例?net frameworkQ,在遵守Lucene索引文g格式的基上,使得Lucene能够q行在各U各Lq_上,pȝ理员可以根据当前的q_适合的语a来合理的选?/p>
索引和搜索的关系
索引是现代搜索引擎的核心Q徏立烦引的q程是把源数据处理成非常方便查询的索引文g的过E。ؓ什么烦引这么重要呢Q试想你现在要在大量的文档中搜烦含有某个关键词的文档Q那么如果不建立索引的话你就需要把q些文档序的读入内存,然后查这个文章中是不是含有要查找的关键词Q这L话就会耗费非常多的旉Q想x索引擎可是在毫秒U的旉内查扑և要搜索的l果的。这是׃建立了烦引的原因Q你可以把烦引想象成q样一U数据结构,他能够你快速的随机讉K存储在烦引中的关键词Q进而找到该关键词所兌的文档。Lucene 采用的是一U称为反向烦引(inverted indexQ的机制。反向烦引就是说我们l护了一个词/短语表,对于q个表中的每个词/短语Q都有一个链表描qC有哪些文档包含了q个?短语。这样在用户输入查询条g的时候,p非常快的得到搜烦l果。我们将在本pd文章的第二部分详l介l?Lucene 的烦引机Ӟ׃ Lucene 提供了简单易用的 APIQ所以即使读者刚开始对全文本进行烦引的机制q不太了解,也可以非常容易的使用 Lucene 对你的文档实现烦引?
Ҏ档徏立好索引后,可以在q些索引上面q行搜烦了。搜索引擎首先会Ҏ索的关键词进行解析,然后再在建立好的索引上面q行查找Q最l返回和用户输入的关键词相关联的文档?/p>
Lucene 软g包分?/b> Package: org.apache.lucene.document q个包提供了一些ؓ装要烦引的文档所需要的c,比如 Document, Field。这P每一个文档最l被装成了一?Document 对象? Package: org.apache.lucene.analysis q个包主要功能是Ҏ档进行分词,因ؓ文档在徏立烦引之前必要q行分词Q所以这个包的作用可以看成是为徏立烦引做准备工作? Package: org.apache.lucene.index q个包提供了一些类来协助创建烦引以及对创徏好的索引q行更新。这里面有两个基的类QIndexWriter ?IndexReaderQ其?IndexWriter 是用来创建烦引ƈd文档到烦引中的,IndexReader 是用来删除烦引中的文档的? Package: org.apache.lucene.search q个包提供了对在建立好的索引上进行搜索所需要的cR比?IndexSearcher ?Hits, IndexSearcher 定义了在指定的烦引上q行搜烦的方法,Hits 用来保存搜烦得到的结?/p>
Lucene包结构功能表 | |
包名 | 功能 |
org.apache.lucene.analysis | 语言分析器,主要用于的切词,支持中文主要是扩展此c?/p> |
org.apache.lucene.document | 索引存储时的文档l构理Q类g关系型数据库的表l构 |
org.apache.lucene.index | 索引理Q包括烦引徏立、删除等 |
org.apache.lucene.queryParser | 查询分析器,实现查询关键词间的运,如与、或、非{?/p> |
org.apache.lucene.search | 索管理,Ҏ查询条gQ检索得到结?/p> |
org.apache.lucene.store | 数据存储理Q主要包括一些底层的I/O操作 |
org.apache.lucene.util | 一些公用类 |
一个简单的搜烦应用E序
假设我们的电脑的目录中含有很多文本文档,我们需要查扑֓些文档含有某个关键词。ؓ了实现这U功能,我们首先利用
Lucene 对这个目录中的文档徏立烦引,然后在徏立好的烦引中搜烦我们所要查扄文档。通过q个例子读者会对如何利?
Lucene 构徏自己的搜索应用程序有个比较清楚的认识?/p>
建立索引
ZҎ档进行烦引,Lucene 提供了五个基的类Q他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介l一下这五个cȝ用途:
Document
Document 是用来描q文档的Q这里的文档可以指一?HTML 面Q一电子邮Ӟ或者是一个文本文件。一?Document 对象由多?Field 对象l成的。可以把一?Document 对象惌成数据库中的一个记录,而每?Field 对象是记录的一个字Dc?
接口?/p>
备注
add(Field field)
d一个字D(FieldQ到Document?/p>
String get(String name)
从文档中获得一个字D对应的文本
Field getField(String name)
由字D名获得字段?/p>
Field[] getFields(String name)
由字D名获得字段值的?/p>
Field
Field 对象是用来描qC个文档的某个属性的Q比如一电子邮件的标题和内容可以用两个 Field 对象分别描述?
即上文所说的“字D”,它是Document的片Dsection?
Field的构造函敎ͼ
Field(String name, String string, boolean store, boolean index, boolean token)?
IndexedQ如果字D|Indexed的,表示q个字段是可索的?
StoredQ如果字D|Stored的,表示q个字段的值可以从索结果中得到?
TokenizedQ如果一个字D|Tokenized的,表示它是有经qAnalyzer转变后成Z个tokens序列Q在q个转变q程tokenization中,Analyzer提取出需要进行烦引的文本Q而剔除一些冗余的词句Q例如:aQthe,they{,详见org.apache.lucene.analysis.StopAnalyzer.ENGLISH_STOP_WORDS和org.apache.lucene.analysis.standard.StandardAnalyzer(String[] stopWords)的APIQ。Token是烦引时候的基本单元Q代表一个被索引的词Q例如一个英文单词,或者一个汉字。因此,所有包含中文的文本都必LTokenized的?
Analyzer
在一个文档被索引之前Q首先需要对文档内容q行分词处理Q这部分工作是?Analyzer 来做的。Analyzer cL一个抽象类Q它有多个实现。针对不同的语言和应用需要选择适合?Analyzer。Analyzer 把分词后的内容交l?IndexWriter 来徏立烦引?
接口?/p>
备注
addDocument(Document doc)
索引d一个文?/p>
addIndexes(Directory[] dirs)
目录中已存在烦引添加到q个索引
addIndexes(IndexReader[] readers)
提供的索引d到这个烦?/p>
optimize()
合ƈ索引q优?/p>
close()
关闭
IndexWriter
IndexWriter ?Lucene 用来创徏索引的一个核心的c,他的作用是把一个个?Document 对象加到索引中来?
Directory
q个cM表了 Lucene 的烦引的存储的位|,q是一个抽象类Q它目前有两个实玎ͼW一个是 FSDirectoryQ它表示一个存储在文gpȝ中的索引的位|。第二个?RAMDirectoryQ它表示一个存储在内存当中的烦引的位置?/p>
熟悉了徏立烦引所需要的q些cdQ我们就开始对某个目录下面的文本文件徏立烦引了Q给ZҎ个目录下的文本文件徏立烦引的源代码?
public class TextFileIndexer {public static void main(String[] args) throws Exception {// fileDir is the directory that contains the text files to be indexed
File fileDir = new File("C:\\index");// indexDir is the directory that hosts Lucene's index files
File indexDir = new File("C:\\luceneIndex");Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter indexWriter = new IndexWriter(FSDirectory.open(indexDir), luceneAnalyzer, true, IndexWriter.MaxFieldLength.LIMITED);File[] textFiles = fileDir.listFiles();
long startTime = new Date().getTime();// Add documents to the index
for (int i = 0; i < textFiles.length; i++) {if (textFiles[i].isFile() && textFiles[i].getName().endsWith(".txt")) {
System.out.println("File " + textFiles[i].getCanonicalPath() + " is being indexed");Reader textReader = new FileReader(textFiles[i]);
Document document = new Document();
document.add(new Field("content", textReader));document.add(new Field("path", textFiles[i].getPath(), Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));indexWriter.addDocument(document);}}indexWriter.optimize();indexWriter.close();
long endTime = new Date().getTime();System.out.println("It took " + (endTime - startTime) + " milliseconds to create an index for the files in the directory " + fileDir.getPath());}}
我们注意到类 IndexWriter 的构造函数需要三个参敎ͼW一个参数指定了所创徏的烦引要存放的位|,他可以是一?File 对象Q也可以是一?FSDirectory 对象或?RAMDirectory 对象。第二个参数指定?Analyzer cȝ一个实玎ͼ也就是指定这个烦引是用哪个分词器Ҏ挡内容进行分词。第三个参数是一个布型的变量,如果?true 的话׃表创Z个新的烦引,?false 的话׃表在原来索引的基上进行操作。接着E序遍历了目录下面的所有文本文档,qؓ每一个文本文档创Z一?Document 对象。然后把文本文档的两个属性:路径和内容加入到了两?Field 对象中,接着在把q两?Field 对象加入?Document 对象中,最后把q个文档?IndexWriter cȝ add Ҏ加入到烦引中厅R这h们便完成了烦引的创徏。接下来我们q入在徏立好的烦引上q行搜烦的部分?/p>
搜烦文档
Query
q是一个抽象类Q他有多个实玎ͼ比如TermQuery, BooleanQuery, PrefixQuery. q个cȝ目的是把用户输入的查询字W串装成Lucene能够识别的Query?
Term
Term是搜索的基本单位Q一个Term对象有两个Stringcd的域l成。生成一个Term对象可以有如下一条语句来完成QTerm term = new Term(“fieldName?”queryWord?; 其中W一个参C表了要在文档的哪一个Field上进行查找,W二个参C表了要查询的关键词?
TermQuery
TermQuery是抽象类Query的一个子c,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName?”queryWord?); 它的构造函数只接受一个参敎ͼ那就是一个Term对象?
IndexSearcher
IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只ȝ方式打开一个烦引,所以可以有多个IndexSearcher的实例在一个烦引上q行操作?
Hits
Hits是用来保存搜索的l果的?/p>
介绍完这些搜索所必须的类之后Q我们就开始在之前所建立的烦引上q行搜烦了,清单2l出了完成搜索功能所需要的代码?
如何d一个文档到索引?/b>
Document document = new Document();
document.add(new Field("content",textReader));
document.add(new Field("path",textFiles[i].getPath(), Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));
indexWriter.addDocument(document);
//最后不要忘C关闭
indexWriter.close();
首先W一行创Zc?Document 的一个实例,它由一个或者多个的?Field)l成。你可以把这个类惌成代表了一个实际的文档Q比如一?HTML 面Q一?PDF 文档Q或者一个文本文件。而类 Document 中的域一般就是实际文档的一些属性。比如对于一?HTML 面Q它的域可能包括标题Q内容,URL {。我们可以用不同cd?Field 来控制文档的哪些内容应该索引Q哪些内容应该存储。如果想获取更多的关?Lucene 的域的信息,可以参?Lucene 的帮助文档。代码的W二行和W三行ؓ文档d了两个域Q每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别?content"?path"。分别存储了我们需要烦引的文本文g的内容和路径。最后一行把准备好的文档dC索引当中?/p>
从烦引中删除文档
cIndexReader负责从一个已l存在的索引中删除文档?
File indexDir = new File("C:\\luceneIndex");
IndexReader ir = IndexReader.open(indexDir);
ir.delete(1);
ir.delete(new Term("path","C:\\file_to_index\lucene.txt"));
ir.close();
W二行用静态方?IndexReader.open(indexDir) 初始化了c?IndexReader 的一个实例,q个Ҏ的参数指定了索引的存储\径。类 IndexReader 提供了两U方法去删除一个文档,如程序中的第三行和第四行所C。第三行利用文档的编h删除文档。每个文档都有一个系l自动生成的~号。第四行删除了\径ؓ"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文g路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文档不能被索到Q但是ƈ没有物理上删除该文档。Lucene 只是通过一个后~名ؓ .delete 的文件来标记哪些文档已经被删除。既然没有物理上删除Q我们可以方便的把这些标Cؓ删除的文档恢复过来,如清?3 所C,首先打开一个烦引,然后调用Ҏ ir.undeleteAll() 来完成恢复工作?/p>
恢复已删除文?/b>
File indexDir = new File("C:\\luceneIndex");
IndexReader ir = IndexReader.open(indexDir);
ir.undeleteAll();
ir.close();
如何物理上删除文?/b>
File indexDir = new File("C:\\luceneIndex");
Analyzer luceneAnalyzer = new StandardAnalyzer();
IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false);
indexWriter.optimize();
indexWriter.close();
W三行创Zc?IndexWriter 的一个实例,q且打开了一个已l存在的索引。第 4 行对索引q行清理Q清理过E中把所有标Cؓ删除的文档物理删除?/p>
提高索引性能
利用 LuceneQ在创徏索引的工E中你可以充分利用机器的g资源来提高烦引的效率。当你需要烦引大量的文gӞ你会注意到烦引过E的瓉是在往盘上写索引文g的过E中。ؓ了解册个问? Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?q运的是QLucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大以及往盘上写索引文g的频率?
1Q合q因子(mergeFactorQ?
q个参数军_了在 Lucene 的一个烦引块中可以存攑֤文档以及把盘上的索引块合q成一个大的烦引块的频率。比如,如果合ƈ因子的值是 10Q那么当内存中的文档数达?10 的时候所有的文档都必d到磁盘上的一个新的烦引块中。ƈ且,如果盘上的索引块的隔数辑ֈ 10 的话Q这 10 个烦引块会被合ƈ成一个新的烦引块。这个参数的默认值是 10Q如果需要烦引的文档数非常多的话q个值将是非怸合适的。对批处理的索引来讲Qؓq个参数赋一个比较大的g得到比较好的索引效果?
2Q最合q文档数
q个参数也会影响索引的性能。它军_了内存中的文档数臛_辑ֈ多少才能它们写回磁盘。这个参数的默认值是10Q如果你有够的内存Q那么将q个值尽量设的比较大一些将会显著的提高索引性能?
3Q最大合q文档数
q个参数军_了一个烦引块中的最大的文档数。它的默认值是 Integer.MAX_VALUEQ将q个参数讄为比较大的值可以提高烦引效率和索速度Q由于该参数的默认值是整型的最大|所以我们一般不需要改动这个参数?
int mergeFactor = 10;
int minMergeDocs = 10;
int maxMergeDocs = Integer.MAX_VALUE;
IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
indexWriter.mergeFactor = mergeFactor;
indexWriter.minMergeDocs = minMergeDocs;
indexWriter.maxMergeDocs = maxMergeDocs;
下面我们来看一下这三个参数取不同的值对索引旉的媄响,注意参数值的不同和烦引之间的关系。我们ؓq个实验准备?10000 个测试文档。表 1 昄了测试结果?
?/b>1Q测试结?/b>
![]()
通过?1Q你可以清楚地看C个参数对索引旉的媄响。在实践中,你会l常的改变合q因子和最合q文档数的值来提高索引性能。只要你有够大的内存,你可以ؓ合ƈ因子和最合q文档数q两个参数赋量大的g提高索引效率Q另外我们一般无需更改最大合q文档数q个参数的|因ؓpȝ已经默认它讄成了最大?/p>
我们采用的方案如下:
先看?/p>
上图的流E大致上是这LQ?
手机端向PC端发送聊天内?
1、手机端E序通过Socketq接服务器端的ServerSocket
2、然后服务器端根据手机Mobile客户端发送过来统一规范的报文或聊天内容Q进行解?
3、然后将解析的内容,再用smack框架转发到openfire服务?
4、最后由openfire服务器向客户端(BS、CS、PhoneClientQ程序发送聊天信息。这里的客户端可以是pc上的览器,pc上的桌面应用Q手机应用等
5、PC客户端BSE序Q用http bind方式监听Q的长连接监听到openfire服务器发送过来的数据Q直接在面中显C?/p>
同样QPC客户端向手机端发送聊天内?
1、PC客户端(BSQ可以直接用http bindQxmpp 提供的httph的长q接方式Q直接向openfire服务器发送聊天数据;
2、然后openfire服务器接收到聊天内容的时候,q时候socket服务器中的smack框架中有一个聊天内容的监听?
3、监听到PC端向openfire发送的内容后,会用socket的流向手机端发送我们定义好的报文或是聊天内?
4、手机端的socket会不停的轮询Q可以模拟心跛_长连接的方式Q,判断是否有消息到达,如果有则昄
而普通的聊天E序的流E则是客L发送信息到openfire服务器,openfire服务器再消息{发给其他客户端。他们省Msocket服务器这部分Q那我们Z么要加上socket服务器这部分呢?
我们q样做也是有自己的道理的Q?
首先Q如果让手机端自己实现向openfire服务器发送程序的代码Q那工作量是相当大的。因为每个手机^C用的语言都不同,每个q_都需要实现向openfire服务器发送聊天信息的报文。这其实是在做重复的工作,而且每个q_实现向手机端发送报文信息的技术会让每个手机端的开发h员都要学会一套和openfire交互的代码。这势必会重复工作、重复相同业务的代码。所以,把这些代码放在一个tcp/ip的socket中{服务器进行统一发送,q也是有好处的?
其次Q把所以发送消息在报文在socket服务器完成,可以对业务进行一个统一的处理、消息过滤?/p>
手机端被否决的解x案,供参?/font>
手机端用http长连接的方式Q这个是不行?/p>
其一、手机的Ud|络不稳定,长连接会l常断掉Q当然你可以自动q行重连
其二、长q接一直连接在服务器上Q占用服务器资源。当然你可以使用心蟩式长q接或是轮询方式
其三、手机端一直连接服务器会用手机端用户的网l带宽流量(量不是免费的,客户会怎么惻I
其四、手机端一直连着服务器,Ҏ机的电量也有消耗(现在决电量也是一个问题)