??xml version="1.0" encoding="utf-8" standalone="yes"?>
目前已经开发有 release 出来的版本有 BeanUtils, Betwixt, CLI, Collections, DBCP, Digester, Discovery, EL, FileUpload, HttpClient, Jelly, Jexl, JXPath, Lang, Latka, Logging, Modeler, Net, Pool, Validator {等
每个版本都不太一? 随时都有更新的可? 至于q没?release 出来正式的版? 有一些项? 可能也正?使用?!! 也是有可能因为其他项目做出来的一些元? 可以抽出来共用的, 例如目前 struts 用的 Resources ( Resource bundle component ) , 也被列入 SandBox 研发? 准备 release 更符合所有项目的 lg.
jakarta Z要有 commons q个 project 出现, 是希望大家不用重复开发一L(fng)lg, 辑ֈ reusable ?目的 !! 而且他们都有Ҏ(gu)使用的特? 也是各个 jakarta committer 牛h们的_֍C, 因此, l对不能?q这一?open source project !! 各位亲爱?java 同胞(yu)?.................
BeanUtils 介绍
当我在选择要先介绍哪一个组? 实在犹U?jin)很? 因ؓ(f)每一个实在都是精? 久久无法做出军_, 所以呢, 只好按照是否 release 再按照字母的先后, 做一个排? 希望大家明白 ....
所?BeanUtils Z要开发呢, 每个工程师或许在?JavaBean 的时? 都会(x)乖乖地去?getters ?setters, 是 getXXX() ?setXXX() methods, 但是当你?object 是动态生的, 也许是用文g, 也许?其他原因, 那你该如何去存取数据?!!
几个例子你可能会(x)用到 BeanUtils, 当然, q是已经存在的项目了(jin)
BeanUtils API 介绍
BeanUtils ?Java API 主要?package d四项
BeanUtils.PropertyUtils 介绍
基本? 我假讑֤家对 JavaBean 的开发都没有问题, 是?getters ?setters 都了(jin)解是什? 先假? Employee class
public class Employee {
public Address getAddress(String type);
public void setAddress(String type, Address address);
public Employee getSubordinate(int index);
public void setSubordinate(int index, Employee subordinate);
public String getFirstName();
public void setFirstName(String firstName);
public String getLastName();
public void setLastName(String lastName);
}
Employee employee = ...;
String firstName = (String)PropertyUtils.getSimpleProperty(employee, "firstName");
String lastName = (String)PropertyUtils.getSimpleProperty(employee, "lastName");
.............
PropertyUtils.setSimpleProperty(employee, "firstName", firstName);
PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
Employee employee = ...;
int index = ...;
String name = "subordinate[" + index + "]";
Employee subordinate = (Employee)PropertyUtils.getIndexedProperty(employee, name);
Employee employee = ...;
int index = ...;
Employee subordinate = (Employee)PropertyUtils.getIndexedProperty(employee, "subordinate", index);
Employee employee = ...;
Address address = ...;
PropertyUtils.setMappedProperty(employee, "address(home)", address);
Employee employee = ...;
Address address = ...;
PropertyUtils.setMappedProperty(employee, "address", "home", address);
String city = (String)PropertyUtils.getNestedProperty(employee, "address(home).city");
千万要记? BeanUtils 是要让你随心(j)所Ʋ? 所以呢 index , mapped 当然都可以这样?nbsp;
Employee employee = ...;
String city = (String) PropertyUtils.getProperty(employee, "subordinate[3].address(home).city");
BeanUtils.DynaBean and BeanUtils.DynaClass 介绍
所有的 Dynamic JavaBean 都是实现 DynaBean ?DynaClass q两?interface, 也可能会(x)用到 DynaProperty class 来存?properties . 我们Z要用?Dynamic JavaBean ? 例如, 你从数据库取出来 的数? 有时候可能是三个栏位, 有时候是四个栏位, 如果我们对于每个 Bean 都要d一?class, ׃(x)?? 所以对于每一U?javabean 我们p定他的属性有哪些, 接着可以?PropertyUtils 来将他的数值取 ? 如此, 可以减少很多开发工? ?Struts 的课E中, 很多人问到我, 请问每一?ActionForm 都必d ?java 文g? 当然, 不需要的, 否则一个网一?ActionForm ( 假设都不一?), 那么, q么费旉 的工? Zq要使用 Struts 来作?Framework ? 所以我们都是?org.apache.struts.action.DynaActionForm!!
MutableDynaClass ( since $1.5 ) q是蛮新的一?DynaClass, 是ؓ(f)?jin)动态可以调?properties !
DynaProperty[] props = new DynaProperty[]{
new DynaProperty("address", java.util.Map.class),
new DynaProperty("subordinate", mypackage.Employee[].class),
new DynaProperty("firstName", String.class),
new DynaProperty("lastName", String.class)
};
BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
DynaBean employee = dynaClass.newInstance();
employee.set("address", new HashMap());
employee.set("subordinate", new mypackage.Employee[0]);
employee.set("firstName", "Fred");
employee.set("lastName", "Flintstone");
Connection conn = ...;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select account_id, name from customers");
Iterator rows = (new ResultSetDynaClass(rs)).iterator();
while (rows.hasNext()) {
DynaBean row = (DynaBean) rows.next();
System.out.println("Account number is " + row.get("account_id") + " and name is " + row.get("name"));
}
rs.close();
stmt.close();
Connection conn = ...; // Acquire connection from pool
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT ...");
RowSetDynaClass rsdc = new RowSetDynaClass(rs);
rs.close();
stmt.close();
...; // Return connection to pool
List rows = rsdc.getRows();
...; // Process the rows as desired
MyBean bean = ...;
DynaBean wrapper = new WrapDynaBean(bean);
String firstName = wrapper.get("firstName");
BeanUtils.ConvertUtils 介绍
在很多情? 例如 struts framework ? 常常用?request.getParameter 的参? 需要{换成 正确的数据类? 所?ConvertUtils 是来处理这些动?
ConvertUtils().convert(java.lang.Object value)
ConvertUtils().convert(java.lang.String[] values, java.lang.Class clazz)
ConvertUtils().convert(java.lang.String value, java.lang.Class clazz)
HttpServletRequest request = ...;
MyBean bean = ...;
HashMap map = new HashMap();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
map.put(name, request.getParameterValues(name));
}
BeanUtils.populate(bean, map);// it will use ConvertUtils for convertings
Converter myConverter = new org.apache.commons.beanutils.converter.IntegerConverter();
ConvertUtils.register(myConverter, Integer.TYPE); // Native type
ConvertUtils.register(myConverter, Integer.class); // Wrapper class
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* @author shaevel
*
*/
public class ReadExcel {
//public static String outputFile="D:\\JTest\\gongye.xls";
/**
* @param args
*/
public static void main(String[] args) {
String outputFile="D:\\gongye.xls";
createXLS(outputFile);
//String inputFile = "D:\\shuaka.xls";
//readXLS(inputFile);
}
public static void createXLS(String outputFile){
try{
// 创徏新的Excel 工作?br /> HSSFWorkbook workbook = new HSSFWorkbook();
// 在Excel工作中Z工作表,其名为缺省?br />
// 如要新徏一名ؓ(f)"效益指标"的工作表Q其语句为:(x)
// HSSFSheet sheet = workbook.createSheet("效益指标");
HSSFSheet sheet = workbook.createSheet();
// 在烦(ch)?的位|创Q最端的行Q?br /> HSSFRow row = sheet.createRow((short)0);
//在烦(ch)?的位|创建单元格Q左上端Q?br /> HSSFCell cell = row.createCell((short) 0);
// 定义单元gؓ(f)字符串类?br />
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cell.setEncoding(HSSFCell.ENCODING_UTF_16);
// 在单元格中输入一些内?br /> cell.setCellValue("我们的故?);
// 新徏一输出文g?br /> FileOutputStream fOut = new FileOutputStream(outputFile);
// 把相应的Excel 工作存?br />
workbook.write(fOut);
fOut.flush();
// 操作l束Q关闭文?br /> fOut.close();
System.out.println("文g生成...");
}catch(Exception e) {
System.out.println("已运?xlCreate() : " + e );
}
}
public static void readXLS(String inputFile){
try{
// 创徏对Excel工作文件的引用
HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(inputFile));
// 创徏对工作表的引用?br /> // 本例是按名引用(让我们假定那张表有着~省?Sheet1"Q?br /> HSSFSheet sheet = workbook.getSheet("Sheet1");
// 也可用getSheetAt(int index)按烦(ch)引引用,
// 在Excel文档中,W一张工作表的缺省烦(ch)引是0Q?br />
// 其语句ؓ(f)QHSSFSheet sheet = workbook.getSheetAt(0);
// d左上端单?br />
for(int i = 0; i < 8; i++){
for(int j =0; j < 6; j++){
HSSFRow row = sheet.getRow(i);
HSSFCell cell = row.getCell((short)j);
// 输出单元内容Qcell.getStringCellValue()是取所在单元的?br />
if(cell.getCellType() == 0){
System.out.print(cell.getNumericCellValue() + " ");
}
if(cell.getCellType() == 1){
System.out.print(cell.getStringCellValue() + " ");
}
}
System.out.print("\n");
}
}catch(Exception e) {
System.out.println("已运行xlRead() : " + e );
}
}
}
<bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
</bean>
但是q种方式有个局限性,如果该方法中既有调用Hibernateq行存储Q也有通过JdbcTemplateq行数据库的写操作,如果在方法执行过E中Q写数据发生异常Ӟ只有U_?jin)事务管理的通过Hibernateq行存储的数据才?x)回滚,而通过JdbcTemplate方式q行操作的数据不?x)进行回滚?/p>
原因是Hibernate与JdbcTemplate使用的是不同DBConnectionQ而且JdbcTemplate未申明相应的事务理Q所以要惛_既用了(jin)HibernateQ也使用?jin)JdbcTemplateq行数据库存储操作的Ҏ(gu)q行事务理Q需要在Spring的配|文件做适当的修改,样例如下Q?nbsp;
<bean id="oaTM" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref bean="oaSessionFactory"/></property>
<property name="dataSource"><ref bean="oaDataSource"/></property>
</bean>
JdbcTemplate和Hibernate能被wrap到同一个事务里。成立需要几Ҏ(gu)Ӟ(x)
1、用同一个datasourceQ?br />
2、事务交由HibernateTransactionManager理Q?br />
3、相关dao以及(qing)service需要用runtime exception体系Q用spring提供的exception可以Q自己封装设计的runtime exception体系也行?
imp
imp
imp
/**
* @author pinghui.zhang
*
*/
public class StringToFile {
/**
* 把字W串写入文本?br />
* @param fileName 生成的文件绝对\?br />
* @param content 文g要保存的内容
* @param enc 文g~码
* @return
*/
public static boolean writeStringToFile(String fileName,String content,String enc) {
File file = new File(fileName);
try {
if(file.isFile()){
file.deleteOnExit();
file = new File(file.getAbsolutePath());
}
OutputStreamWriter os = null;
if(enc==null||enc.length()==0){
os = new OutputStreamWriter(new FileOutputStream(file));
}else{
os = new OutputStreamWriter(new FileOutputStream(file),enc);
}
os.write(content);
os.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public static void main(String args[]){
int[] ids = {995, 996, 997};
StringBuffer presb = new StringBuffer();
StringBuffer sufsb = new StringBuffer();
presb.append("<%@ page language=\"java\" imp
.append("<%@ taglib uri=\"
.append("<%\n")
.append("\tString deptid = \"");
sufsb.append("\"; //只要修改此处卛_\n")
.append("\trequest.setAttribute(\"dept\", com.dadi.oa.system.DepartmentUtil.getDepartmentInfo(new Long(deptid)));\n")
.append("\tString fromurl = request.getRequestURI().substring(request.getRequestURI().lastIndexOf(\"/\") + 1);\n")
.append("%>\n")
.append("<%@ include file=\"body.jsp\"%>");
String content = "";
String fileName = "";
for(int i = 0; i < ids.length; i++){
fileName = "D:\\project1\\OA\\Co
content = presb.toString() + ids[i] + sufsb.toString();
writeStringToFile(fileName, content, "UTF-8");
}
}
}
2007 q?11 ?27 ?/p>
为应用程序添加搜索能力经常是一个常见的需求。本文介l了(jin)一个框Ӟ开发者可以用它以最的付出实现搜烦(ch)引擎功能Q理x(chng)况下只需要一个配|文件。该框架Z若干开源的库和工具Q如 Apache LuceneQSpring 框架Qcpdetector {。它支持多种资源。其中两个典型的例子是数据库资源和文件系l资源。Indexer 寚w|的资源q行索引q传输到中央服务器,之后q些索引可以通过 API q行搜烦(ch)。Spring 风格的配|文件允许清晰灵zȝ自定义和调整。核?API 也提供了(jin)可扩展的接口?
为应用程序添加搜索能力经常是一个常见的需求。尽已l有若干E序库提供了(jin)Ҏ(gu)索基设施的支持,然而对于很多h而言Q用它们从头开始徏立一个搜索引擎将是一个付Z而且可能乏味的过E。另一斚wQ很多的型应用对于搜烦(ch)功能的需求和应用场景h很大的相似性。本文试图以对多数小型应用的适用性ؓ(f)出发点,?Java 语言构徏一个灵zȝ搜烦(ch)引擎框架。用这个框Ӟ多数情Ş下可以以最的付出建立起一个搜索引擎。最理想的情况下Q甚臛_需要一个配|文件。特D的情Ş下,可以通过灉|地对框架q行扩展满需求。当?dng)如题所qͼq都是借助开源工L(fng)力量?
![]() ![]() |
Apache Lucene 是开发搜索类应用E序时最常用?Java cdQ我们的框架也将Z它。ؓ(f)?jin)下文更好的描述Q我们需要先?jin)解一些有?Lucene 和搜索的基础知识。注意,本文不关注烦(ch)引的文g格式、分词技术等话题?
从用L(fng)角度来看Q搜索的q程是通过关键字在某种资源中寻扄定的内容的过E。而从计算机的角度来看Q实现这个过E可以有两种办法。一是对所有资源逐个与关键字匚wQ返回所有满_配的内容Q二是如同字怸样事先徏立一个对应表Q把关键字与资源的内容对应v来,搜烦(ch)时直接查找这个表卛_。显而易见,W二个办法效率要高得多。徏立这个对应表事实上就是徏立逆向索引Qinverted indexQ的q程?
Lucene ?Doug Cutting ?Java 开发的用于全文搜烦(ch)的工具库。在q里Q我假设读者对其已有基本的?jin)解Q我们只对一些重要的概念要介l。要深入?jin)解可以参?参考资?/font> 中列出的相关文章和图书。下面这些是 Lucene 里比较重要的cR?
使用 Lucene 来进行编制烦(ch)引的q程大致为:(x)输入的数据源统一为字W串或者文本流的Ş式,然后从数据源提取数据Q创建合适的
![]() ![]() |
要徏立一个通用的框Ӟ必须对不同情늚共性进行抽象。反映到设计需要注意两炏V一是要提供扩展接口Q二是要量降低模块之间的耦合E度。我们的框架很简单地分ؓ(f)两个模块Q烦(ch)引模块和搜烦(ch)模块。烦(ch)引模块在不同的机器上各自q行对资源的索引Qƈ把烦(ch)引文Ӟ事实上,下面我们?x)说刎ͼq有元数据)(j)l一传输到同一个地方(可以是在q程服务器上Q也可以是在本地Q。搜索模块则利用q些从多个烦(ch)引模块收集到的数据完成用L(fng)搜烦(ch)h?/p>
?1 展现?jin)整体的框架。可以看刎ͼ两个模块之间相对是独立的Q它们之间的兌不是通过代码Q而是通过索引和元数据。在下文中,我们会(x)详细介绍如何Z开源工兯计和实现q两个模块?/p>
![]() ![]() |
可以q行索引的对象有很多Q如文g、网c(din)RSS Feed {。在我们的框架中Q我们定义可以进行烦(ch)引的一c?/strong>对象?em>资源。从实现l节上来_(d)从一个资源中可以提取出多? 前面提到Q从资源中收集到的烦(ch)引被l一传送到同一个地方,以被搜烦(ch)模块所用。显焉?jin)?ch)引之外,搜烦(ch)模块需要对资源有更多的?jin)解Q如资源的名U、搜索该资源后搜索结果的呈现格式{。这些额外的附加信息UCؓ(f)资源?em>元数?/em>。元数据和烦(ch)引数据一同被攉hQ放|到某个特定的位|?/p>
要地介绍q资源的概念之后Q我们首先ؓ(f)其定义一?
public interface Resource {
// RequestProcessor 对象被动C资源中提?DocumentQƈq回提取的数?
public int extractDocuments(ResourceProcessor processor);
// d?DocumentListener 在每一?Document 对象被提取出时被调用
public void addDocumentListener(DocumentListener l);
// q回资源的元数据
public ResourceMetaData getMetaData();
}
其中元数据包含的字段见下表。在下文中,我们q(sh)(x)对元数据的用途做更多的介l?/p>
属?/th> | cd | 含义 |
---|---|---|
resourceName | String | 资源?strong>唯一名称 |
resourceDescription | String | 资源的介l性文?/td> |
hitTextPattern | String | 当文档被搜烦(ch)到时Q这?pattern 规定?jin)结果显C的格式 |
searchableFields | String[] | 可以被搜索的字段名称 |
?
public interface DocumentListener extends EventListener { public void documentExtracted(Document doc); } |
Z(jin)让烦(ch)引模块能够知道所有需要被索引的资源,我们在这里?Spring 风格?XML 文g配置索引模块中的所有组Ӟ其是所有资源。?zhn)可以?下蝲部分 查看一个示例配|文件?/p>
![]() |
|
Z以上内容Q我们可以大致描q出索引模块工作的过E:(x)
在这个过E中Q有两个地方值得注意?/p>
W一Q对资源可以注册
W二点很昄Q在q个q程中,
Ҏ(gu)件系l资源的索引通常从一个基目录开始,递归处理每个需要进行烦(ch)引的文g。该资源有一个字W串数组cd?
除了(jin)所有文件共有的文g名、文件\径、文件大和修改旉{?FieldQ不同类型的文g需要有不同的处理方法。ؓ(f)?jin)保留灵zL,我们使用 Strategy 模式装对不同类型文件的处理方式。ؓ(f)此我们抽象出一?
public interface DocumentBuilder { Document buildDocument(InputStream is); } |
![]() |
|
不同?
文gcd | 常用扩展?/th> | 可以使用的解析办?/th> |
---|---|---|
U文本文?/td> | txt | 无需cd解析 |
RTF 文档 | rtf | 使用 |
Word 文档Q非 OOXML 格式Q?/td> | doc | Apache POI Q可配合使用 POI ScratchpadQ?/td> |
PowerPoint 演示文稿Q非 OOXML 格式Q?/td> | xls | Apache POI Q可配合使用 POI ScratchpadQ?/td> |
PDF 文档 | PDFBoxQ可能中文支持欠佻I(j) | |
HTML 文档 | htm, html | JTidy, Cobra |
q里?Word 文gZQ给Z个简单的参考实现?/p>
// WordDocument ?Apache POI Scratchpad 中的一个类 Document buildDocument(InputStream is) { String bodyText = null; try { WordDocument wordDoc = new WordDocument(is); StringWriter sw = new StringWriter(); wordDoc.writeAllText(sw); sw.close(); bodyText = sw.toString(); } catch (Exception e) { throw new DocumentHandlerException("Cannot extract text from a Word document", e); } if ((bodyText != null) && (bodyText.trim().length() > 0)) { Document doc = new Document(); doc.add(new Field("body", bodyText, Field.Store.YES, Field.Index.TOKENIZED)); return doc; } return null; } |
那么如何选择合适的 Strategy 来处理文件呢QUNIX pȝ下的 file(1) 工具提供?jin)?magicnumber 获取文gcd的功能,我们可以使用
大多数应用用数据库作ؓ(f)怹存储Q对数据库查询结果集索引是一个常见需求?/p>
生成一个数据库l果集资源的实例需要先提供一个查询语句,然后执行查询Q得C个结果集。这个结果集中的内容便是我们需要进行烦(ch)引的对象?co 然而不?
ID = YES, NO
TITLE = YES, TOKENIZED
CONTENT = NO, TOKENIZED
配合q个映射Q我们便可以生成合适类型的
![]() ![]() |
完成对资源的索引之后Q还需要让索引为搜索模块所用。前面我们已l说q这里介l的框架主要用于型应用Q考虑到复杂性,我们采取单地分布在各个机器上的索引汇d一个地方的{略?/p>
汇ȝ(ch)引的传输方式可以有很多方案,比如使用 FTP、HTTP、rsync {。甚至烦(ch)引模块和搜烦(ch)模块可以位于同一台机器上Q这U情况下只需要将索引q行本地拯卛_。同前面cMQ我们定义一?
public interface Transporter { public void transport(File file); } |
?FTP 方式传输ZQ我们?Commons Net 完成传输的操作?/p>
public void transport(File file) throws TransportException { FTPClient client = new FTPClient(); client.connect(host); client.login(username, password); client.changeWorkingDirectory(remotePath); transportRecursive(client, file); client.disconnect(); } public void transportRecursive(FTPClient client, File file) { if (file.isFile() && file.canRead()) { client.storeFile(file.getName(), new FileInputStream(file)); } else if (file.isDirectory()) { client.makeDirectory(file.getName()); client.changeWorkingDirectory(file.getName()); File[] fileList = file.listFiles(); for (File f : fileList) { transportRecursive(client, f); } } } |
对其他传输方案也有各自的Ҏ(gu)q行处理Q具体用哪?
![]() ![]() |
在做?jin)这么多之后Q我们开始接触和用户兌最为紧密的搜烦(ch)模块。注意,我们的框架不包括一个搜索的 Web 前端界面。但是类DL(fng)界面可以在搜索模块的基础上方便地开发出来。基于已l收集好的烦(ch)引进行搜索是个很单的q程。Lucene 已经提供?jin)功能强大?
对不同资源进行搜索的查询Ҏ(gu)q不一栗例如搜索一个论坛里的所有留aӞ我们x(chng)的一般是留言的标题、作者和内容Q而当搜烦(ch)一?FTP 站点Ӟ我们更多x(chng)的是文g名和文g内容。另一斚wQ我们有时可能会(x)使用一个查询去搜烦(ch)多个资源的结果。这正是之前我们在前面所提到的元数据?
当从
例如搜烦(ch)“具体”q回的搜索结果中包含一?
Field 名称 | Field 内容 |
---|---|
url | http://example.org/article/1.html |
title | CZ标题 |
content | q里是具体的内容?/td> |
那么如果
CZ标题
q里?strong>具体...
上面提到?
可以使用正则表达式和文本解析来实现前面所提到的语法。我们也可以使用 JavaCC 定义
![]() ![]() |
下面列出的是一些与我们所提出的框架所相关或者类似的产品Q?zhn)可以?学习(fn)资料 中更多地?jin)解他们?/p>
OmniFind ?IBM 公司推出的企业搜烦(ch)解决Ҏ(gu)。基?UIMA (Unstructured Information Management Architecture) 技术,它提供了(jin)强大的烦(ch)引和获取信息功能Q支持巨大数量、多U类型的文档资源Q无论是l构化还是非l构化)(j)Qƈ?Lotus®Domino®?WebSphere®Portal 专门q行?jin)优化?/p>
Solr ?Apache 的一个企业的全文检索项目,实现?jin)一个基?HTTP 的搜索服务器Q支持多U资源和 Web 界面理Q它同样建立?Lucene 之上Qƈ?Lucene 做了(jin)很多扩展Q例如支持动态字D及(qing)唯一键,Ҏ(gu)询结果进行动态分l和qo(h){?/p>
使用 Google 的站Ҏ(gu)索功能可以方便而快捷地建立一个站内搜索引擎。但?Google 的站Ҏ(gu)索基?Google 的网l爬虫,所以无法访问受保护的站点内Ҏ(gu)?Intranet 上的资源。另外,Google 所支持的资源类型也是有限的Q我们无法对其进行扩展?/p>
SearchBlox 是一个商业的搜烦(ch)引擎构徏框架。它本n是一?J2EE lgQ和我们的框架类|也支持对|页和文件系l等资源q行索引Q进而进行搜索?/p>
![]() ![]() |
本文介绍的思想试图利用开源的工具解决中小型应用中的常见问题。当?dng)作?f)一个框Ӟ它还有很多不I下面列DZ些可以进行改q的地方?/p>
当需要进行烦(ch)引的资源数目不多Ӟ隔一定的旉q行一ơ完全烦(ch)引不?x)占用很长时间。用一?2G 内存QXeon 2.66G 处理器的服务器进行实际测试,发现Ҏ(gu)据库资源的烦(ch)引占用的旉很少Q一千多条记录花费的旉?1 U到 2 U之内。而对 1400 多个文gq行索引耗时大约十几U。但在大型应用中Q资源的定w是巨大的Q如果每ơ都q行完整的烦(ch)引,耗费的时间会(x)很惊人。我们可以通过跌已经索引的资源内容,删除已不存在的资源内容的索引Qƈq行增量索引来解册个问题。这可能?x)涉及(qing)文件校验和索引删除{?/p>
另一斚wQ框架可以提供查询缓存来提高查询效率。框架可以在内存?sh)徏立一U缓存,q用如 OSCache ?EHCache 实现盘?sh)的二~存。当索引的内容变化不频繁Ӟ使用查询~存更会(x)明显地提高查询速度、降低资源消耗?/p>
我们的框架可以将索引分布在多台机器上。搜索资源时Q查询被 flood 到各个机器上从而获得搜索结果。这样可以免M输烦(ch)引到某一C央服务器的过E。当然也可以Z实现?jin)分布式哈希?QDHTQ的l构?P2P |络Q配合烦(ch)引复?(Replication)Q得应用程序更为安全,可靠Q有伸羃性。在 阅读资料 中给Z(jin) 一关于构建分布式环境下全文搜索的可行性的论文?
目前我们的框架ƈ没有涉及(qing)到安全性。除?jin)依赖资源本w的讉K控制Q如受保护的|页和文件系l等Q之外,我们q可以从两方面增强框架本w的安全性:(x)
![]() ![]() |
通过上文的介l,我们认识?jin)一个可扩展的框Ӟq(ch)引模块和搜烦(ch)模块两部分组成。它可以灉|地适应不同的应用场景。如果需要更独特的需求,框架本n预留?jin)可以扩展的接口Q我们可以通过实现q些接口完成功能的定制。更重要的是q一切都是徏立在开源Y件的基础之上。希望本文能为?zhn)揭示开源的力量Q体验用开源工L(fng)装?zhn)自己的解x(chng)案所带来的莫大快乐?/p>