`
flashdream8
  • 浏览: 680708 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Lucene+Paoding构建SSH2系统的站内搜索

阅读更多

目标:创建一个具有高度可移植的,定时创建索引的站内搜索。
途径:dic和index都放到程序中去。

准备:
1   Lucene
Lucene Java(以下简称Lucene)目前可用版本是2.4.0,关于Lucene的详细信息请查看http://lucene.apache.org/java/docs/index.html


2 Paoding
Qieqie同学的伟大作品、优秀的Lucene中文分词组件,目前的版本为paoding-analysis-2.0.4-beta,对应的Lucene的版本为2.2。关于Paoding的具体信息请查看http://code.google.com/p/paoding/


3 下载最新的paoding-analysis-2.0.4-beta版本(里面包含了lucene-core-2.2.0.jar, lucene-analyzers-2.2.0.jar,lucene-highlighter-2.2.0.jar, junit.jar, commons-logging.jar)。


>>>>> 本文为原创,需要转载的朋友请注明: http://jnotnull.iteye.com  谢谢支持!<<<<<

开始工作:
   1 试运行
打开下载包中的examples文件夹,运行一下吧(注意一下编码)。


   2 集成到SSH2系统中去 (系统结构Action->service->dao)
1)  由于SSH2系统是web系统,因此在配置Paoding上就有可能和第一步有些不同。
直接把paoding文件夹下的src文件夹下的所有文件和dic文件夹复制到你的项目中去。打开paoding-dic-home.properties文件,修改paoding.dic.home.config-fisrt=this,使得程序知道该配置文件,修改paoding.dic.home=classpath:dic,使得字典在该项目中。保存就可以了。在这里我使用了classpath:dic是为了增加可移植性。如果使用绝对路径没有什么可说的了,但是如果你是制定为classpath:dic,则需要修改一下Paoding中的代码了。找到PaodingMaker.java的setDicHomeProperties方法,修改File dicHomeFile = getFile(dicHome);为

Java代码 复制代码
  1. File dicHomeFile2 = getFile(dicHome);   
  2.         String path="";   
  3.         try {   
  4.             path = URLDecoder.decode(dicHomeFile2.getPath(),"UTF-8");   
  5.         } catch (UnsupportedEncodingException e) {   
  6.             e.printStackTrace();   
  7.         }   
  8.     File dicHomeFile = new File(path);  
File dicHomeFile2 = getFile(dicHome);
		String path="";
		try {
			path = URLDecoder.decode(dicHomeFile2.getPath(),"UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	File dicHomeFile = new File(path);


目的是解码,不然如果你的词典路径中有空格和汉字会出现找不到字典的异常。

2)表结构

Sql代码 复制代码
  1. CREATE TABLE `news` (   
  2.   `id` int(11) NOT NULL auto_increment,   
  3.   `title` varchar(255) default NULL,   
  4.   `details` mediumtext,   
  5.   `author` varchar(255) default NULL,   
  6.   `publisher` varchar(100) default NULL,   
  7.   `clicks` int(11) default NULL,   
  8.   `source` varchar(255) default NULL,   
  9.   `addtime` datetime default NULL,   
  10.   ` category ` varchar(100) default NULL,   
  11.   `keywords` varchar(255) default NULL,   
  12.   PRIMARY KEY  (`id`)   
  13. ) ENGINE=InnoDB DEFAULT CHARSET=gbk;  
    3 正式实施编码 
       编写站内搜索分为两步:创建索引和进行搜索,所需类:SearchAction.java和TaskAction.java(同一目录) 
1) 创建索引 
主要任务:从已有的txt文件中读取上一次进行索引的最后一条新闻的id号,然后从业务逻辑中查找大于这个id号的所有新闻进行索引,最后把这次最后的一条新闻id写入txt文件中。在这里要处理好路径的问题。在这里所有的记录id号的txt文件都放到了action目录下面。 
新建TaskAction,增加如下方法
Java代码 复制代码
  1. public void createIndex() {   
  2.         String path;   
  3.         try {      
  4. //两个参数:创建索引的位置  和 上一次创建索引最后的新闻id所在文件   
  5.     createNewsIndex(getPath(TaskAction.class"date/index/news"),"newsid.txt");   
  6.         } catch (Exception e) {   
  7.             e.printStackTrace();   
  8.         }   
  9.     }   
  10.   
  11. public String getPath(Class clazz, String textName)   
  12.             throws IOException {   
  13.         String path = (URLDecoder.decode(   
  14.                 clazz.getResource(textName).toString(), "UTF-8")).substring(6);        
  15.         return path;   
  16.     }   
  17.   
  18. public void createNewsIndex(String path,String textName) throws Exception {   
  19.         String newsId = "0";   
  20.            
  21.         newsId = readText(TaskAction.class, textName);   
  22.         if (null ==newsId || "".equals(newsId))   
  23.             newsId = "0";   
  24.   
  25.         // 使用paoding中文分析器   
  26.         Analyzer analyzer = new PaodingAnalyzer();   
  27.         FSDirectory directory = FSDirectory.getDirectory(path);   
  28.         System.out.println(directory.toString());   
  29.         IndexWriter writer = new IndexWriter(directory, analyzer, isEmpty(TaskAction.class, textName));   
  30.         Document doc = new Document();   
  31.   
  32.         // 从业务逻辑层读取大于当前id的信息   
  33.         List list = newsManageService.getNewsBigId(Integer.parseInt(newsId));   
  34.         Iterator iterator = list.iterator();   
  35.         News news = new News();   
  36.         while (iterator.hasNext()) {   
  37.             doc = new Document();   
  38.             news = (News) iterator.next();   
  39.             doc.add(new Field("id""" + news.getId(), Field.Store.YES,   
  40.                     Field.Index.UN_TOKENIZED));   
  41.             doc.add(new Field("title""" + news.getTitle(), Field.Store.YES,   
  42.                     Field.Index.TOKENIZED));   
  43.             doc.add(new Field("author""" + news.getAuthor(), Field.Store.YES,   
  44.                     Field.Index.TOKENIZED));   
  45.             doc.add(new Field("details"""  
  46.                     + Constants.splitAndFilterString(news.getDetails()),   
  47.                     Field.Store.YES, Field.Index.TOKENIZED,   
  48.                     Field.TermVector.WITH_POSITIONS_OFFSETS));   
  49.             doc.add(new Field("addtime""" + news.getAddtime(),   
  50.                     Field.Store.YES, Field.Index.TOKENIZED));   
  51.             doc.add(new Field("keywords""" + news.getKeywords(),   
  52.                     Field.Store.YES, Field.Index.TOKENIZED));   
  53.             System.out.println("Indexing file " + news.getName() + "...");   
  54.             articleId = String.valueOf(news.getId());   
  55.             try {   
  56.                 writer.addDocument(doc);   
  57.             } catch (IOException e) {   
  58.                 e.printStackTrace();   
  59.             }   
  60.         }   
  61.         // 优化并关闭   
  62.         writer.optimize();   
  63.         writer.close();   
  64.   
  65.         // 将我索引的最后一篇文章的id写入文件   
  66.         String content = WriteText(TaskAction.class,   
  67.                 textName, newsId);   
  68.     }      
  69.   
  70. public boolean isEmpty(Class clazz, String textName) throws Exception {   
  71.         String articleId = "0";   
  72.         boolean isEmpty = true;   
  73.         articleId = ContentReader.readText(clazz, textName);   
  74.         if (null == articleId || "".equals(articleId))   
  75.             articleId = "0";   
  76.         if (!articleId.equals("0"))   
  77.             isEmpty = false;   
  78.         System.out.println(clazz.getName()+" "+isEmpty);   
  79.         return isEmpty;   
  80.     }   
  81.   
  82. //该方法参考了paoding中example中的一个方法。   
  83. public String readText(Class clazz, String textName)   
  84.             throws IOException {   
  85.         InputStream in = clazz.getResourceAsStream(textName);   
  86.         Reader re = new InputStreamReader(in, "UTF-8");   
  87.         char[] chs = new char[1024];   
  88.         int count;   
  89.         String content = "";   
  90.         while ((count = re.read(chs)) != -1) {   
  91.             content = content + new String(chs, 0, count);   
  92.         }   
  93.         return content;   
  94.     }   
  95.   
  96. public String WriteText(Class clazz, String textName, String text)   
  97.             throws IOException {   
  98.         String path = (URLDecoder.decode(   
  99.                 clazz.getResource(textName).toString(), "UTF-8")).substring(6);   
  100.         System.out.println(path);   
  101.         File file = new File(path);   
  102.         BufferedWriter bw = new BufferedWriter(new FileWriter(file));   
  103.         String temp = text;   
  104.         bw.write(temp);   
  105.         bw.close();   
  106.         return temp;   
  107.     }  



2)进行搜索

Java代码 复制代码
  1. public void searchIndex(String path, String keywords) throws Exception {   
  2.         String[] FIELD = { "title""details" };   
  3.         String QUERY = keywords;   
  4.   
  5.         Analyzer analyzer = new PaodingAnalyzer();   
  6.         FSDirectory directory = FSDirectory.getDirectory(path);   
  7.         IndexReader reader = IndexReader.open(directory);   
  8.         String queryString = QUERY;   
  9.         BooleanClause.Occur[] flags = new BooleanClause.Occur[] {   
  10.                 BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };   
  11.         Query query = MultiFieldQueryParser.parse(queryString, FIELD, flags,   
  12.                 analyzer);   
  13.   
  14.         Searcher searcher = new IndexSearcher(directory);   
  15.         query = query.rewrite(reader);   
  16.         System.out.println("Searching for: " + query.toString());   
  17.         Hits hits = searcher.search(query);   
  18.   
  19.         NewsDTO news = new NewsDTO();   
  20.         String highLightText = "";   
  21.   
  22.         for (int i = 0; i < hits.length(); i++) {   
  23.   
  24.             Document doc = hits.doc(i);   
  25.             String title1 = doc.get("title");   
  26.             String contents1 = doc.get("details");   
  27.   
  28.             SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter(   
  29.                     """");   
  30.   
  31.             Highlighter highlighter = new Highlighter(simpleHTMLFormatter,   
  32.                     new QueryScorer(query));   
  33.             highlighter.setTextFragmenter(new SimpleFragmenter(200));   
  34.   
  35.             if (contents1 != null) {   
  36.                 TokenStream tokenStream = analyzer.tokenStream("details",   
  37.                         new StringReader(contents1));   
  38.                 highLightText = highlighter.getBestFragment(tokenStream,   
  39.                         contents1);   
  40.             }   
  41.             news = new NewsDTO();   
  42.             news.setId(Integer.parseInt(doc.get("id")));   
  43.             news.setName(doc.get("title"));   
  44.             news.setDetails(highLightText);   
  45.             news.setAddtime(doc.get("addtime"));   
  46.             news.setAuthor(doc.get("author"));   
  47.             searchResultItem.add(news);   
  48.         }   
  49.         reader.close();   
  50.   
  51.     }  


   核心代码已经基本完成了,还有一个加亮显示,非常不错的哦。

3)再来一个定时创建索引:
   定义一下bean

Java代码 复制代码
  1.            
  2. <bean id="myTask" class="edu.cumt.jnotnull.action.TaskAction">   
  3.         <property name="newsManageService">   
  4.             <ref bean="newsManageService" />   
  5.         </property>   
  6.     </bean>   
  7.   
  8.     <bean id="entity"  
  9.         class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">   
  10.         <property name="targetObject">   
  11.             <ref local="myTask" />   
  12.         </property>   
  13.         <property name="targetMethod">   
  14.             <value>createIndex</value>   
  15.         </property>   
  16.     </bean>   
  17.   
  18.     <bean id="cron"  
  19.         class="org.springframework.scheduling.quartz.CronTriggerBean">   
  20.         <property name="jobDetail">   
  21.             <ref bean="entity" />   
  22.         </property>   
  23.         <property name="cronExpression">   
  24.             <value>0 0-5 2 * * ?</value>   
  25.         </property>   
  26.     </bean>   
  27.   
  28.     <bean autowire="no"  
  29.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean">   
  30.         <property name="triggers">   
  31.             <list>   
  32.                 <ref local="cron" />   
  33.             </list>   
  34.         </property>   
  35.     </bean>      
  36.            
  37.       
		


这样就可以在夜里面让他自动促发了。
分享到:
评论
1 楼 fengsky491 2008-12-05  
能不能提供整个项目文件,谢了。

相关推荐

    基于Java的Luncene的compass框架说明使用技术文档.pdf

    Lucene提供了一套API用于解析、过滤、分析文件并构建和使用索引。开发者可以将Lucene视为支持全文索引的数据库系统。 - **Compass**:Compass被定义为面向域模型的搜索框架,这意味着它必须支持对象搜索、持久化...

    Compass技术文档

    下面是一个基于SSH(Struts2+Spring+Hibernate)架构的Compass使用示例: 1. **添加依赖库**:在SSH项目基础上添加Compass及相关依赖库,具体包括: - `compass-2.1.2.jar` - `compass-index-patch.jar` - `...

    java开源包2

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    Java资源包01

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包8

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包1

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包11

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包3

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包6

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包5

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包10

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包4

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包7

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包9

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包101

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

Global site tag (gtag.js) - Google Analytics