搜索引擎优化高级编程:php版(用Lucene来建立一个索引你应用程序的文本内容由Lucene)
优采云 发布时间: 2021-12-22 14:09搜索引擎优化高级编程:php版(用Lucene来建立一个索引你应用程序的文本内容由Lucene)
将搜索功能添加到您的 Web网站 是增强用户浏览体验的最简单方法之一,但在您的应用程序中集成搜索引擎并不总是那么容易。为了帮助您为 Java 应用程序提供灵活的搜索引擎,我将解释如何使用 Lucene,这是一个极其灵活的开源搜索引擎。
Lucene 将直接与您的 Web 应用程序集成。它由 Jakarta Apache 工作组用 Java 编写。您的 Java 应用程序可以使用 Lucene 作为任何搜索功能的核心。 Lucene 可以处理任何类型的文本数据;但它没有对 Word、Excel、PDF 和 XML 的内置支持。但是仍然有一些解决方案可以让 Lucene 支持它们中的每一个。
Lucene 重要的是它只是一个搜索引擎,所以没有内置的 Web 图形用户界面和 Webcrawler。要将 Lucene 集成到您的 Web 应用程序中,您需要编写一个显示查询表单的 servlet 或 JSP 页面,以及另一个列出结果的页面。
使用Lucene创建索引
你的应用程序的文本内容被Lucene索引并作为一系列索引文件保存在文件系统中。 Lucene 可以接受表示单个内容的 Document 对象,例如网页或 PDF 文件。您的应用程序负责将其内容转换为 Lucene 可以理解的文档对象。
每个文档由一个或多个 Field 对象组成。这些字段收录名称和值,很像散点图中的条目。每个字段对应一条信息,与您需要查询或显示的搜索结果相关。例如,标题应该在搜索结果中使用,因此它将作为字段添加到文档对象中。这些字段可以被索引也可以不被索引,原创数据也可以存储在索引中。创建搜索结果页面时,索引中存储的字段很有用。对搜索无用的字段,例如唯一 ID,不需要编入索引,只需保存即可。
field 也可以被标记化,这意味着分析程序会将输入到该字段的内容分解为搜索引擎可以使用的标记。 Lucene 自带了多种分析程序,但我只会使用最强大的分析程序——StandardAnalyzer 类。
StandardAnalyzer 类会将文本的所有内容转为小写,并删除一些常用的停用词。暂停词是像“a”、“the”和“in”这样的词。它们是内容中非常常见的词,但它们对搜索毫无用处。分析器还会分析搜索查询,这意味着查询会找到匹配的部分。例如,文本“Thedogisagoldenretriever(这只狗是金毛猎犬)”将被处理为“doggoldenretriever”作为索引。当用户搜索“aGoldenDog”时,分析程序会对查询进行处理,将其转化为“goldendog”,与我们的内容相符。
我们的例子将使用业务对象(DataAccessObject、DAO),前者是Java应用程序开发的常用模式。我要使用的 DAO--ProductDAO,参见 ListingA。
为了使这个演示程序简单,我不打算使用数据库,DAO 将只收录 Product 对象的集合。在这个例子中,我将把 ListingB 中的产品对象转化为文档以进行索引。
Indexer 类在 ListingC 中。它将负责将 Product 转换为 Lucene 文档,同时还负责创建 Lucene 索引。
产品类别中的字段为 ID 名称、简短描述和详细描述。通过使用 Field 类的 UnIndexed 方法,ID 将存储为非索引、非标记字段。通过使用字段类的Keyword 方法,名称和简短描述将作为索引的非标记字段存储。搜索引擎会查询内容字段,内容字段将收录产品名称、简短描述和详细描述字段。
添加完所有文档后,优化索引并关闭索引编写器,以便您可以使用索引。 Lucene 的大多数实现都使用增量索引。在增量索引中,索引中已有的文档独立更新,而不是每次删除索引并创建一个新索引。
运行查询
创建查询并在索引中搜索结果比创建索引更容易。您的应用程序将要求用户提供一个搜索查询,它可以是一个简单的词。 Lucene 有一些更高级的 Query 类用于布尔搜索或整句搜索。
高级查询的一个示例是“MutualFund”(共同基金)ANDstock*(股票),它将搜索收录短语 MutualFund 和以股票开头的单词(例如股票、股票或什至长袜)的文档。
________________________________________
获取有关 Lucene 中查询的更多信息
语法页面
LuceneWeb网站 将提供更详细的信息。
________________________________________
Searcher 类放在 ListingD 中,它负责查找你在 Lucene 索引中使用的词。对于这个演示程序,我使用了一个简单的查询,它只是一个字符串,没有使用任何高级查询功能。我使用 QueryParser 类从查询字符串创建查询 (Query) 对象。 QueryParser 类使用 StandardAnalyzer 类将查询字符串分解为标记,去除暂停词,并将字符串转换为小写。
查询被传递给一个 IndexSearcher 对象。 IndexSearcher 将在索引文件系统中初始化。 IndexSearcher 的搜索方法将接受这个查询并返回一个 Hits 对象。该命中对象收录作为 Lucene 文档对象的搜索结果,以及结果的长度。使用命中对象的 Doc 方法将检索命中对象中的每个文档。
文档对象收录我添加到索引器文档的字段。其中一些字段已保存,但未标记化,您可以从文档中提取它们。示例应用程序将使用搜索引擎运行查询,然后显示它找到的产品名称。
________________________________________
运行演示程序
要运行本文中的示例程序,您需要从 Lucene 的 Web网站 下载最新版本的 Lucene 二进制发行版。 Lucene发行版的lucene-1.3-rc1.jar文件需要添加到你的Java类路径中才能运行这个demo程序。演示程序将在 com.greenninja.lucene.Demo 类运行的目录下创建一个名为 index 的索引目录。您还需要安装JDK。一个典型的命令行是: java-cpc:/java/lucene-1.3-rc1/lucene-1.3-rc1.jar;.com.greenninja.lucene.Demo(见图A)。本示例中使用的示例数据收录在 ProductDAO 类中。此查询是 Demo 类的一部分。
________________________________________
图一
命令行示例
列表A
/*
*这是用于检索产品的数据访问对象。
*
*为了 Lucene 文章的目的,它只是一个类
*创建产品对象并保留主题集合。
*
*它可以与数据库、EJB 通信或从 XML 加载数据。
*
*
*/
packagecom.greenninja.lucene;
importjava.util.*;
publicclassProductDAO
{
privateMapmap=newHashMap();
publicvoidinit()
{
Productproduct1=newProduct("1E344","BlizzardConvertible",
“暴雪是当今市场上最好的敞篷车,拥有 120 马力、6 个座位和方向盘。”,
“暴雪敞篷车是一种革命性的汽车,它看起来像一辆小型货车,但有一个折叠式车顶,就像一辆跑车。把我们柴油发动机的所有动力都用在了我们所有的新燃料电池动力系统中。”);
map.put(product1.getId(),product1);
Productproduct2=newProduct("R5TS7","Truck3000",
“我们的Truck3000 型号有各种形状和尺寸,包括自卸车、垃圾车和皮卡车。垃圾车有完整的 3 年保修期。”,
“Truck3000 与我们的推土机建造在同一个基础上,并且可以配备可选的悬停器附件以进行全地形旅行。”);
map.put(product2.getId(),product2);
Productproduct3=newProduct("VC456","i954d-bMotorcycle",
“*敏*感*词*的每侧都配备了侧车,以获得额外的稳定性和转弯能力。”,
“我们的*敏*感*词*拥有与其他产品相同的保修,并且不保证骑自行车的里程数。每辆*敏*感*词*都配有任何防风衣、护目镜、头盔和护目镜。”);
map.put(product3.getId(),product3);
}
/**
*Getsa采集ofalloftheproducts
*
*@returnalloftheproducts
*/
public采集getAllProducts()
{
returnmap.values();
}
/**
*Getsaproduct,giventheuniqueid
*
*@paramidtheuniqueid
*@returntheProductobject,ornulliftheidwasn'tfound
*/
publicProductgetProduct(Stringid)
{
if(map.containsKey(id))
{
return(Product)map.get(id);
}
//未找到产品ID
returnnull;
}
}
列表B
/*
*用于展示业务的 Lucene 文章的示例类
*值对象。
*
*
*/
packagecom.greenninja.lucene;
公共类产品
{
privateStringname;
privateStringshortDescription;
privateStringlongDescription;
privateStringid;
/**
*Constructortocreateanewproduct
*/
publicProduct(Stringi,Stringn,Stringsd,Stringld)
{
this.id=i;
this.name=n;
this.shortDescription=sd;
this.longDescription=ld;
}
/**
*Gettheuniqueid
*
*@return
*/
publicStringgetId()
{
返回标识;
}
/**
*获取网页的描述
*
*@return
*/
publicStringgetLongDescription()
{
returnlongDescription;
}
/**
*获取产品名称
*
*@return
*/
publicStringgetName()
{
返回名称;
}
/**
*获取产品的简短摘要说明,用于目录
*
*@return
*/
publicStringgetShortDescription()
{
returnshortDescription;
}
/**
*设置产品的唯一标识
*
*@paramstring
*/
publicvoidsetId(Stringstring)
{
id=string;
}
/**
*设置产品的详细说明
*
*@paramstring
*/
publicvoidsetLongDescription(Stringstring)
{
longDescription=string;
}
/**
*设置产品名称
*
*@paramstring
*/
publicvoidsetName(Stringstring)
{
名称=字符串;
}
/**
*设置产品的概述
*
*@paramstring
*/
publicvoidsetShortDescription(Stringstring)
{
shortDescription=string;
}
}
列表C
/*
*CreatedonJun19,2003
*
*
*/
packagecom.greenninja.lucene;
importjava.io.IOException;
importjava.util.采集;
importjava.util.Iterator;
importorg.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.analysis.standard.StandardAnalyzer;
importorg.apache.lucene.document.Document;
importorg.apache.lucene.document.Field;
importorg.apache.lucene.index.IndexWriter;
publicclassIndexer
{
protectedIndexWriterwriter=null;
protectedAnalyzeranalyzer=newStandardAnalyzer();
publicvoidinit(StringindexPath)throwsIOException
{
//每次运行时创建一个新索引
writer=newIndexWriter(indexPath,analyzer,true);
}
publicvoidbuildIndex()throwsIOException
{
//从DAO中获取产品
ProductDAOdao=newProductDAO();
dao.init();
采集products=dao.getAllProducts();
Iteratoriter=products.iterator();
while(iter.hasNext())
{
Productproduct=(Product)iter.next();
//将产品转换为文档。
Documentdoc=newDocument();
//为productid创建一个未索引的、未标记的、存储的字段
doc.add(Field.UnIndexed("productId",product.getId()));
//创建一个索引的、未标记的、存储的名称字段
doc.add(Field.Keyword("name",product.getName()));
//为简短描述创建一个索引的、未标记的、存储的字段
doc.add(Field.Keyword("short",product.getShortDescription()));
//为所有内容创建一个索引的、标记化的、未存储的字段
Stringcontent=product.getName()+""+product.getShortDescription()+
""+product.getLongDescription();
doc.add(Field.Text("content",content));
//将文档添加到索引中
试试
{
writer.addDocument(doc);
System.out.println("Document"+product.getName()+" addedtoindex.");
}
catch(IOExceptione)
{
System.out.println("错误添加文档:"+e.getMessage());
}
}
//优化索引
writer.optimize();
//关闭索引
writer.close();
}
}
列表D
/*
*CreatedonJun19,2003
*
*
*/
packagecom.greenninja.lucene;
importjava.io.IOException;
importorg.apache.lucene.analysis.Analyzer;
importorg.apache.lucene.analysis.standard.StandardAnalyzer;
importorg.apache.lucene.queryParser.ParseException;
importorg.apache.lucene.queryParser.QueryParser;
importorg.apache.lucene.search.Hits;
importorg.apache.lucene.search.IndexSearcher;
importorg.apache.lucene.search.Query;
publicclassSearcher
{
protectedAnalyzeranalyzer=newStandardAnalyzer();
publicHitssearch(StringindexPath,StringqueryString)throwsIOException,ParseException
{
//Lucene 索引搜索器类,它使用索引上的查询
IndexSearcherindexSearcher=newIndexSearcher(indexPath);
//使用我们的内容字段、查询字符串和分析器进行查询
Queryquery=QueryParser.parse(queryString,"content",analyzer);
Hitshits=indexSearcher.search(query);
回传;
}
}
备注:
生成索引:
javaorg.apache.lucene.demo.IndexFilesc:/test/
搜索索引:
javaorg.apache.lucene.demo.SearchFiles
生成网页索引
C:/Tomcat/webapps/ROOT>javaorg.apache.lucene.demo.IndexHTML-create-indexc:/
Tomcat/webapps/ROOT/index/c:/test/