重庆专业做网站安徽鲲鹏建设集团有限公司网站

web/2025/9/26 13:43:45/文章来源:
重庆专业做网站,安徽鲲鹏建设集团有限公司网站,网站建设行业广告语,登陆不了建设银行网站lucene学习教程 1.1 什么是lucene Lucene是一个全文搜索框架#xff0c;而不是应用产品。因此它并不像www.baidu.com 或者google Desktop那么拿来就能用#xff0c;它只是提供了一种工具让你能实现这些产品。 2 lucene的工作方式 lucene提供的服务实际包含两部分#xf…lucene学习教程   1.1 什么是lucene     Lucene是一个全文搜索框架而不是应用产品。因此它并不像www.baidu.com 或者google Desktop那么拿来就能用它只是提供了一种工具让你能实现这些产品。   2 lucene的工作方式     lucene提供的服务实际包含两部分一入一出。所谓入是写入即将你提供的源本质是字符串写入索引或者将其从索引中删除所谓出是读出即向用户提供全文搜索服务让用户可以通过关键词定位源。 2.1写入流程     源字符串首先经过analyzer处理包括分词分成一个个单词去除stopword可选。 将源中需要的信息加入Document的各个Field中并把需要索引的Field索引起来把需要存储的Field存储起来。     将索引写入存储器存储器可以是内存或磁盘。 2.2读出流程     用户提供搜索关键词经过analyzer处理。 对处理后的关键词搜索索引找出对应的Document。 用户根据需要从找到的Document中提取需要的Field。       3 一些需要知道的概念 3.1 analyzer     Analyzer是分析器它的作用是把一个字符串按某种规则划分成一个个词语并去除其中的无效词语这里说的无效词语是指英文中的“of”、“the”中文中的“的”、“地”等词语这些词语在文章中大量出现但是本身不包含什么关键信息去掉有利于缩小索引文件、提高效率、提高命中率。   分词的规则千变万化但目的只有一个按语义划分。这点在英文中比较容易实现因为英文本身就是以单词为单位的已经用空格分开而中文则必须以某种方法将连成一片的句子划分成一个个词语。具体划分方法下面再详细介绍这里只需了解分析器的概念即可。 3.2 document   用户提供的源是一条条记录它们可以是文本文件、字符串或者数据库表的一条记录等等。一条记录经过索引之后就是以一个Document的形式存储在索引文件中的。用户进行搜索也是以Document列表的形式返回。 3.3 field     一个Document可以包含多个信息域例如一篇文章可以包含“标题”、“正文”、“最后修改时间”等信息域这些信息域就是通过Field在Document中存储的。     Field有两个属性可选存储和索引。通过存储属性你可以控制是否对这个Field进行存储通过索引属性你可以控制是否对该Field进行索引。这看起来似乎有些废话事实上对这两个属性的正确组合很重要下面举例说明还是以刚才的文章为例子我们需要对标题和正文进行全文搜索所以我们要把索引属性设置为真同时我们希望能直接从搜索结果中提取文章标题所以我们把标题域的存储属性设置为真但是由于正文域太大了我们为了缩小索引文件大小将正文域的存储属性设置为假当需要时再直接读取文件我们只是希望能从搜索解果中提取最后修改时间不需要对它进行搜索所以我们把最后修改时间域的存储属性设置为真索引属性设置为假。上面的三个域涵盖了两个属性的三种组合还有一种全为假的没有用到事实上Field不允许你那么设置因为既不存储又不索引的域是没有意义的。 3.4 term   term是搜索的最小单位它表示文档的一个词语term由两部分组成它表示的词语和这个词语所出现的field。 3.5 tocken     tocken是term的一次出现它包含trem文本和相应的起止偏移以及一个类型字符串。一句话中可以出现多次相同的词语它们都用同一个term表示但是用不同的tocken每个tocken标记该词语出现的地方。 3.6 segment     添加索引时并不是每个document都马上添加到同一个索引文件它们首先被写入到不同的小文件然后再合并成一个大索引文件这里每个小文件都是一个segment。   4 lucene的结构 lucene包括core和sandbox两部分其中core是lucene稳定的核心部分sandbox包含了一些附加功能例如highlighter、各种分析器。 Lucene core有七个包analysisdocumentindexqueryParsersearchstoreutil。 4.1 analysis Analysis包含一些内建的分析器例如按空白字符分词的WhitespaceAnalyzer添加了stopwrod过滤的StopAnalyzer最常用的StandardAnalyzer。 4.2 document Document包含文档的数据结构例如Document类定义了存储文档的数据结构Field类定义了Document的一个域。 4.3 index Index包含了索引的读写类例如对索引文件的segment进行写、合并、优化的IndexWriter类和对索引进行读取和删除操作的 IndexReader类这里要注意的是不要被IndexReader这个名字误导以为它是索引文件的读取类实际上删除索引也是由它完成 IndexWriter只关心如何将索引写入一个个segment并将它们合并优化IndexReader则关注索引文件中各个文档的组织形式。 4.4 queryParser QueryParser包含了解析查询语句的类lucene的查询语句和sql语句有点类似有各种保留字按照一定的语法可以组成各种查询。 Lucene有很多种Query类它们都继承自Query执行各种特殊的查询QueryParser的作用就是解析查询语句按顺序调用各种 Query类查找出结果。 4.5 search Search包含了从索引中搜索结果的各种类例如刚才说的各种Query类包括TermQuery、BooleanQuery等就在这个包里。 4.6 store Store包含了索引的存储类例如Directory定义了索引文件的存储结构FSDirectory为存储在文件中的索引RAMDirectory为存储在内存中的索引MmapDirectory为使用内存映射的索引。 4.7 util Util包含一些公共工具类例如时间和字符串之间的转换工具。 5 如何建索引 5.1 最简单的能完成索引的代码片断 Java代码 IndexWriter writer new IndexWriter(“/data/index/”, new StandardAnalyzer(), true);   Document doc new Document();   doc.add(new Field(title, lucene introduction, Field.Store.YES, Field.Index.TOKENIZED));   doc.add(new Field(content, lucene works well, Field.Store.YES, Field.Index.TOKENIZED));   writer.addDocument(doc);   writer.optimize();   writer.close();  下面我们分析一下这段代码。 首先我们创建了一个writer并指定存放索引的目录为“/data/index”使用的分析器为StandardAnalyzer第三个参数说明如果已经有索引文件在索引目录下我们将覆盖它们。 然后我们新建一个document。 我们向document添加一个field名字是“title”内容是“lucene introduction”对它进行存储并索引。 再添加一个名字是“content”的field内容是“lucene works well”也是存储并索引。 然后我们将这个文档添加到索引中如果有多个文档可以重复上面的操作创建document并添加。 添加完所有document我们对索引进行优化优化主要是将多个segment合并到一个有利于提高索引速度。 随后将writer关闭这点很重要。 对创建索引就这么简单 当然你可能修改上面的代码获得更具个性化的服务。 5.2 将索引直接写在内存 你需要首先创建一个RAMDirectory并将其传给writer代码如下 Java代码 Directory dir new RAMDirectory();   IndexWriter writer new IndexWriter(dir, new StandardAnalyzer(), true);   Document doc new Document();   doc.add(new Field(title, lucene introduction, Field.Store.YES, Field.Index.TOKENIZED));   doc.add(new Field(content, lucene works well, Field.Store.YES, Field.Index.TOKENIZED));   writer.addDocument(doc);   writer.optimize();   writer.close();  5.3 索引文本文件 如果你想把纯文本文件索引起来而不想自己将它们读入字符串创建field你可以用下面的代码创建field Field field new Field(content, new FileReader(file)); 这里的file就是该文本文件。该构造函数实际上是读去文件内容并对其进行索引但不存储。 6 如何维护索引 索引的维护操作都是由IndexReader类提供。 6.1 如何删除索引 lucene提供了两种从索引中删除document的方法一种是 void deleteDocument(int docNum) 这种方法是根据document在索引中的编号来删除每个document加进索引后都会有个唯一编号所以根据编号删除是一种精确删除但是这个编号是索引的内部结构一般我们不会知道某个文件的编号到底是几所以用处不大。另一种是 void deleteDocuments(Term term) 这种方法实际上是首先根据参数term执行一个搜索操作然后把搜索到的结果批量删除了。我们可以通过这个方法提供一个严格的查询条件达到删除指定document的目的。 下面给出一个例子 Java代码 Directory dir FSDirectory.getDirectory(PATH, false);   IndexReader reader IndexReader.open(dir);   Term term new Term(field, key);   reader.deleteDocuments(term);   reader.close();  6.2 如何更新索引 lucene并没有提供专门的索引更新方法我们需要先将相应的document删除然后再将新的document加入索引。例如 Java代码 Directory dir FSDirectory.getDirectory(PATH, false);   IndexReader reader IndexReader.open(dir);   Term term new Term(“title”, “lucene introduction”);   reader.deleteDocuments(term);   reader.close();     IndexWriter writer new IndexWriter(dir, new StandardAnalyzer(), true);   Document doc new Document();   doc.add(new Field(title, lucene introduction, Field.Store.YES, Field.Index.TOKENIZED));   doc.add(new Field(content, lucene is funny, Field.Store.YES, Field.Index.TOKENIZED));   writer.addDocument(doc);   writer.optimize();   writer.close();  7 如何搜索 lucene的搜索相当强大它提供了很多辅助查询类每个类都继承自Query类各自完成一种特殊的查询你可以像搭积木一样将它们任意组合使用完成一些复杂操作另外lucene还提供了Sort类对结果进行排序提供了Filter类对查询条件进行限制。你或许会不自觉地拿它跟SQL语句进行比较“lucene能执行and、or、order by、where、like ‘%xx%’操作吗”回答是“当然没问题” 7.1 各种各样的Query 下面我们看看lucene到底允许我们进行哪些查询操作 7.1.1 TermQuery 首先介绍最基本的查询如果你想执行一个这样的查询“在content域中包含‘lucene’的document”那么你可以用TermQuery Term t new Term(content, lucene; Query query new TermQuery(t); 7.1.2 BooleanQuery 如果你想这么查询“在content域中包含java或perl的document”那么你可以建立两个TermQuery并把它们用BooleanQuery连接起来 Java代码 TermQuery termQuery1 new TermQuery(new Term(content, java);   TermQuery termQuery 2 new TermQuery(new Term(content, perl);   BooleanQuery booleanQuery new BooleanQuery();   booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD);   booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD);  7.1.3 WildcardQuery 如果你想对某单词进行通配符查询你可以用WildcardQuery通配符包括’?’匹配一个任意字符和’*’匹配零个或多个任意字符例如你搜索’use*’你可能找到’useful’或者’useless’ Java代码 Query query new WildcardQuery(new Term(content, use*);   7.1.4 PhraseQuery 你可能对中日关系比较感兴趣想查找‘中’和‘日’挨得比较近5个字的距离内的文章超过这个距离的不予考虑你可以 Java代码 PhraseQuery query new PhraseQuery();   query.setSlop(5);   query.add(new Term(content , “中”));   query.add(new Term(“content”, “日”));  那么它可能搜到“中日合作……”、“中方和日方……”但是搜不到“中国某高层领导说日本欠扁”。 7.1.5 PrefixQuery 如果你想搜以‘中’开头的词语你可以用PrefixQuery Java代码 PrefixQuery query new PrefixQuery(new Term(content , 中);  7.1.6 FuzzyQuery FuzzyQuery用来搜索相似的term使用Levenshtein算法。假设你想搜索跟‘wuzza’相似的词语你可以 Java代码 Query query new FuzzyQuery(new Term(content, wuzza);  你可能得到‘fuzzy’和‘wuzzy’。 7.1.7 RangeQuery 另一个常用的Query是RangeQuery你也许想搜索时间域从20060101到20060130之间的document你可以用RangeQuery Java代码 RangeQuery query new RangeQuery(new Term(“time”, “20060101”), new Term(“time”, “20060130”), true);  最后的true表示用闭合区间。 7.2 QueryParser 看了这么多Query你可能会问“不会让我自己组合各种Query吧太麻烦了”当然不会lucene提供了一种类似于SQL语句的查询语句我们姑且叫它lucene语句通过它你可以把各种查询一句话搞定lucene会自动把它们查分成小块交给相应Query执行。下面我们对应每种Query演示一下 TermQuery可以用“field:key”方式例如“content:lucene”。 BooleanQuery中‘与’用‘’‘或’用‘ ’例如“content:java contenterl”。 WildcardQuery仍然用‘?’和‘*’例如“content:use*”。 PhraseQuery用‘~’例如“content:中日~5”。 PrefixQuery用‘*’例如“中*”。 FuzzyQuery用‘~’例如“content: wuzza ~”。 RangeQuery用‘[]’或‘{}’前者表示闭区间后者表示开区间例如“time:[20060101 TO 20060130]”注意TO区分大小写。 你可以任意组合query string完成复杂操作例如“标题或正文包括lucene并且时间在20060101到20060130之间的文章”可以表示为“ (title:lucene content:lucene) time:[20060101 TO 20060130]”。代码如下 Java代码 Directory dir FSDirectory.getDirectory(PATH, false);   IndexSearcher is new IndexSearcher(dir);   QueryParser parser new QueryParser(content, new StandardAnalyzer());   Query query parser.parse((title:lucene content:lucene) time:[20060101 TO 20060130];   Hits hits is.search(query);   for (int i 0; i hits.length(); i)   {   Document doc hits.doc(i);   System.out.println(doc.get(title);   }   is.close();  首先我们创建一个在指定文件目录上的IndexSearcher。 然后创建一个使用StandardAnalyzer作为分析器的QueryParser它默认搜索的域是content。 接着我们用QueryParser来parse查询字串生成一个Query。 然后利用这个Query去查找结果结果以Hits的形式返回。 这个Hits对象包含一个列表我们挨个把它的内容显示出来。 7.3 Filter filter的作用就是限制只查询索引的某个子集它的作用有点像SQL语句里的where但又有区别它不是正规查询的一部分只是对数据源进行预处理然后交给查询语句。注意它执行的是预处理而不是对查询结果进行过滤所以使用filter的代价是很大的它可能会使一次查询耗时提高一百倍。 最常用的filter是RangeFilter和QueryFilter。RangeFilter是设定只搜索指定范围内的索引QueryFilter是在上次查询的结果中搜索。 Filter的使用非常简单你只需创建一个filter实例然后把它传给searcher。继续上面的例子查询“时间在20060101到20060130之间的文章”除了将限制写在query string中你还可以写在RangeFilter中 Java代码 Directory dir FSDirectory.getDirectory(PATH, false);   IndexSearcher is new IndexSearcher(dir);   QueryParser parser new QueryParser(content, new StandardAnalyzer());   Query query parser.parse(title:lucene content:lucene;   RangeFilter filter new RangeFilter(time, 20060101, 20060230, true, true);   Hits hits is.search(query, filter);   for (int i 0; i hits.length(); i)   {   Document doc hits.doc(i);   System.out.println(doc.get(title);   }   is.close();  7.4 Sort 有时你想要一个排好序的结果集就像SQL语句的“order by”lucene能做到通过Sort。 Sort sort new Sort(“time”); //相当于SQL的“order by time” Sort sort new Sort(“time”, true); // 相当于SQL的“order by time desc” 下面是一个完整的例子 Java代码 Directory dir FSDirectory.getDirectory(PATH, false);   IndexSearcher is new IndexSearcher(dir);   QueryParser parser new QueryParser(content, new StandardAnalyzer());   Query query parser.parse(title:lucene content:lucene;   RangeFilter filter new RangeFilter(time, 20060101, 20060230, true, true);   Sort sort new Sort(“time”);   Hits hits is.search(query, filter, sort);   for (int i 0; i hits.length(); i)   {   Document doc hits.doc(i);   System.out.println(doc.get(title);   }   is.close();  8 分析器 在前面的概念介绍中我们已经知道了分析器的作用就是把句子按照语义切分成一个个词语。英文切分已经有了很成熟的分析器 StandardAnalyzer很多情况下StandardAnalyzer是个不错的选择。甚至你会发现StandardAnalyzer也能对中文进行分词。 但是我们的焦点是中文分词StandardAnalyzer能支持中文分词吗实践证明是可以的但是效果并不好搜索“如果”会把“牛奶不如果汁好喝”也搜索出来而且索引文件很大。那么我们手头上还有什么分析器可以使用呢core里面没有我们可以在sandbox里面找到两个 ChineseAnalyzer和CJKAnalyzer。但是它们同样都有分词不准的问题。相比之下用StandardAnalyzer和 ChineseAnalyzer建立索引时间差不多索引文件大小也差不多CJKAnalyzer表现会差些索引文件大且耗时比较长。 要解决问题首先分析一下这三个分析器的分词方式。StandardAnalyzer和ChineseAnalyzer都是把句子按单个字切分也就是说 “牛奶不如果汁好喝”会被它们切分成“牛 奶 不 如 果 汁 好 喝”而CJKAnalyzer则会切分成“牛奶 奶不 不如 如果 果汁 汁好好喝”。这也就解释了为什么搜索“果汁”都能匹配这个句子。 以上分词的缺点至少有两个匹配不准确和索引文件大。我们的目标是将上面的句子分解成“牛奶 不如 果汁好喝”。这里的关键就是语义识别我们如何识别“牛奶”是一个词而“奶不”不是词语我们很自然会想到基于词库的分词法也就是我们先得到一个词库里面列举了大部分词语我们把句子按某种方式切分当得到的词语与词库中的项匹配时我们就认为这种切分是正确的。这样切词的过程就转变成匹配的过程而匹配的方式最简单的有正向最大匹配和逆向最大匹配两种说白了就是一个从句子开头向后进行匹配一个从句子末尾向前进行匹配。基于词库的分词词库非常重要词库的容量直接影响搜索结果在相同词库的前提下据说逆向最大匹配优于正向最大匹配。 当然还有别的分词方法这本身就是一个学科我这里也没有深入研究。回到具体应用我们的目标是能找到成熟的、现成的分词工具避免重新发明车轮。经过网上搜索用的比较多的是中科院的ICTCLAS和一个不开放源码但是免费的JE-Analysis。ICTCLAS有个问题是它是一个动态链接库 java调用需要本地方法调用不方便也有安全隐患而且口碑也确实不大好。JE-Analysis效果还不错当然也会有分词不准的地方相比比较方便放心。 9 性能优化 一直到这里我们还是在讨论怎么样使lucene跑起来完成指定任务。利用前面说的也确实能完成大部分功能。但是测试表明lucene的性能并不是很好在大数据量大并发的条件下甚至会有半分钟返回的情况。另外大数据量的数据初始化建立索引也是一个十分耗时的过程。那么如何提高lucene的性能呢下面从优化创建索引性能和优化搜索性能两方面介绍。 9.1 优化创建索引性能 这方面的优化途径比较有限IndexWriter提供了一些接口可以控制建立索引的操作另外我们可以先将索引写入RAMDirectory再批量写入FSDirectory不管怎样目的都是尽量少的文件IO因为创建索引的最大瓶颈在于磁盘IO。另外选择一个较好的分析器也能提高一些性能。 9.1.1 通过设置IndexWriter的参数优化索引建立 setMaxBufferedDocs(int maxBufferedDocs) 控制写入一个新的segment前内存中保存的document的数目设置较大的数目可以加快建索引速度默认为10。 setMaxMergeDocs(int maxMergeDocs) 控制一个segment中可以保存的最大document数目值较小有利于追加索引的速度默认Integer.MAX_VALUE无需修改。 setMergeFactor(int mergeFactor) 控制多个segment合并的频率值较大时建立索引速度较快默认是10可以在建立索引时设置为100。 9.1.2 通过RAMDirectory缓写提高性能 我们可以先把索引写入RAMDirectory达到一定数量时再批量写进FSDirectory减少磁盘IO次数。 Java代码 FSDirectory fsDir FSDirectory.getDirectory(/data/index, true);   RAMDirectory ramDir new RAMDirectory();   IndexWriter fsWriter new IndexWriter(fsDir, new StandardAnalyzer(), true);   IndexWriter ramWriter new IndexWriter(ramDir, new StandardAnalyzer(), true);   while (there are documents to index)   {   ... create Document ...   ramWriter.addDocument(doc);   if (condition for flushing memory to disk has been met)   {   fsWriter.addIndexes(new Directory[] { ramDir });   ramWriter.close();   ramWriter new IndexWriter(ramDir, new StandardAnalyzer(), true);   }   }  9.1.3 选择较好的分析器 这个优化主要是对磁盘空间的优化可以将索引文件减小将近一半相同测试数据下由600M减少到380M。但是对时间并没有什么帮助甚至会需要更长时间因为较好的分析器需要匹配词库会消耗更多cpu测试数据用StandardAnalyzer耗时133分钟用MMAnalyzer耗时150分钟。 9.2 优化搜索性能 虽然建立索引的操作非常耗时但是那毕竟只在最初创建时才需要平时只是少量的维护操作更何况这些可以放到一个后台进程处理并不影响用户搜索。我们创建索引的目的就是给用户搜索所以搜索的性能才是我们最关心的。下面就来探讨一下如何提高搜索性能。 9.2.1 将索引放入内存 这是一个最直观的想法因为内存比磁盘快很多。Lucene提供了RAMDirectory可以在内存中容纳索引 Java代码 Directory fsDir FSDirectory.getDirectory(“/data/index/”, false);   Directory ramDir new RAMDirectory(fsDir);   Searcher searcher new IndexSearcher(ramDir);  但是实践证明RAMDirectory和FSDirectory速度差不多当数据量很小时两者都非常快当数据量较大时索引文件400MRAMDirectory甚至比FSDirectory还要慢一点这确实让人出乎意料。 而且lucene的搜索非常耗内存即使将400M的索引文件载入内存在运行一段时间后都会out of memory所以个人认为载入内存的作用并不大。 9.2.2 优化时间范围限制 既然载入内存并不能提高效率一定有其它瓶颈经过测试发现最大的瓶颈居然是时间范围限制那么我们可以怎样使时间范围限制的代价最小呢 当需要搜索指定时间范围内的结果时可以 1、用RangeQuery设置范围但是RangeQuery的实现实际上是将时间范围内的时间点展开组成一个个BooleanClause加入到 BooleanQuery中查询因此时间范围不可能设置太大经测试范围超过一个月就会抛BooleanQuery.TooManyClauses可以通过设置 BooleanQuery.setMaxClauseCount(int maxClauseCount)扩大但是扩大也是有限的并且随着maxClauseCount扩大占用内存也扩大 2、用RangeFilter代替RangeQuery经测试速度不会比RangeQuery慢但是仍然有性能瓶颈查询的90%以上时间耗费在 RangeFilter研究其源码发现RangeFilter实际上是首先遍历所有索引生成一个BitSet标记每个document在时间范围内的标记为true不在的标记为false然后将结果传递给Searcher查找这是十分耗时的。 3、进一步提高性能这个又有两个思路 a、缓存Filter结果。既然RangeFilter的执行是在搜索之前那么它的输入都是一定的就是IndexReader而 IndexReader是由Directory决定的所以可以认为RangeFilter的结果是由范围的上下限决定的也就是由具体的 RangeFilter对象决定所以我们只要以RangeFilter对象为键将filter结果BitSet缓存起来即可。lucene API已经提供了一个CachingWrapperFilter类封装了Filter及其结果所以具体实施起来我们可以cache CachingWrapperFilter对象需要注意的是不要被CachingWrapperFilter的名字及其说明误导 CachingWrapperFilter看起来是有缓存功能但的缓存是针对同一个filter的也就是在你用同一个filter过滤不同 IndexReader时它可以帮你缓存不同IndexReader的结果而我们的需求恰恰相反我们是用不同filter过滤同一个 IndexReader所以只能把它作为一个封装类。 b、降低时间精度。研究Filter的工作原理可以看出它每次工作都是遍历整个索引的所以时间粒度越大对比越快搜索时间越短在不影响功能的情况下时间精度越低越好有时甚至牺牲一点精度也值得当然最好的情况是根本不作时间限制。 下面针对上面的两个思路演示一下优化结果都采用800线程随机关键词随即时间范围 第一组时间精度为秒 方式 直接用RangeFilter 使用cache 不用filter 平均每个线程耗时 10s 1s 300ms 第二组时间精度为天 方式 直接用RangeFilter 使用cache 不用filter 平均每个线程耗时 900ms 360ms 300ms 由以上数据可以得出结论 1、 尽量降低时间精度将精度由秒换成天带来的性能提高甚至比使用cache还好最好不使用filter。 2、 在不能降低时间精度的情况下使用cache能带了10倍左右的性能提高。 9.2.3 使用更好的分析器 这个跟创建索引优化道理差不多索引文件小了搜索自然会加快。当然这个提高也是有限的。较好的分析器相对于最差的分析器对性能的提升在20%以下。 10 一些经验 10.1关键词区分大小写 or AND TO等关键词是区分大小写的lucene只认大写的小写的当做普通单词。 10.2 读写互斥性 同一时刻只能有一个对索引的写操作在写的同时可以进行搜索 10.3 文件锁 在写索引的过程中强行退出将在tmp目录留下一个lock文件使以后的写操作无法进行可以将其手工删除 10.4 时间格式 lucene只支持一种时间格式yyMMddHHmmss所以你传一个yy-MM-dd HH:mm:ss的时间给lucene它是不会当作时间来处理的 10.5 设置boost 有些时候在搜索时某个字段的权重需要大一些例如你可能认为标题中出现关键词的文章比正文中出现关键词的文章更有价值你可以把标题的boost设置的更大那么搜索结果会优先显示标题中出现关键词的文章没有使用排序的前题下。使用方法 Field. setBoost(float boost);默认值是1.0也就是说要增加权重的需要设置得比1大。   转载声明 本文转自 http://www.javaeye.com/topic/210567 JavaEve博客   Apache Lucene与Lucene.Net——全文检索服务器   Lucene并不是一个爬行搜索引擎也不会自动地索引内容。我们得先将要索引的文档中的文本抽取出来然后再将其加到Lucene索引中。标准的步骤是先初始化一个Analyzer、打开一个IndexWriter、然后再将文档一个接一个地加进去。   十年前在Windows世界中使用开源项目简直是不可想象的一件事。现在.NET程序员在Java平台上验证并开发的企业级软件世界中也开始觉醒了。今天让我们一起来看看流行的全文检索引擎——Apache Lucene与Lucene.Net。Apache Lucene与其兄弟Lucene.Net是经过了大规模测试的产品他们已经为一些著名站点如Wikipedia、CNET及Monster.com提供了搜索功能。因此没人会怀疑其功能与未来的发展。Lucene并不是一个爬行搜索引擎也不会自动地索引内容。我们得先将要索引的文档中的文本抽取出来然后再将其加到Lucene索引中。标准的步骤是先初始化一个Analyzer、打开一个IndexWriter、然后再将文档一个接一个地加进去。一旦完成这些步骤索引就可以在关闭前得到优化同时所做的改变也会生效。这个过程可能比开发者习惯的方式更加手工化一些但却在数据的索引上给予你更多的灵活性。我们可以借助于一个对象模型来完成搜索通过查询来建立条件。其次Lucene可以解析并执行可能由最终用户输入的普通文本搜索字符串。使用.NET 3.5或后续版本的.NET开发者还有第三种选择LINQ to Lucene。其项目主页上有一张图清晰地描述了Lucene的搜索语法与相应的LINQ to Lucene语法的区别。如果你想试一下可以参考Andrew Smith对Lucene.NET的介绍。无论你选择.NET还是Java版本看看Erik Hatcher对Lucene的介绍都会大有好处。查看英文原文Apache Lucene and Lucene.Net – Full Text Search Servers   转载声明 本文转自 http://www.infoq.com/cn/news/2008/11/Lucene Info Q Lucene-2.0学习文档   Lucene是apache组织的一个用java实现全文搜索引擎的开源项目。其功能非常的强大api也很简单。总得来说用Lucene来进行建立和搜索和操作数据库是差不多的(有点像)Document可以看作是数据库的一行记录Field可以看作是数据库的字段。用lucene实现搜索引擎就像用JDBC实现连接数据库一样简单。Lucene2.0它与以前广泛应用和介绍的Lucene 1.4.3并不兼容。Lucene2.0的下载地址是http://apache.justdn.org/lucene/java/大家先看一个例子通过这个例子来对lucene的一个大概的认识。一个Junit测试用例(为了让代码清晰好看我们将异常都抛出)a)    这是一个建立文件索引的例子public void testIndexHello() throws IOException    {        Date date1 new Date();                //可以说是创建一个新的写入工具        //第一个参数是要索引建立在哪个目录里        //第二个参数是新建一个文本分析器,这里用的是标准的大家也可以自己写一个        //第三个参数如果是true在建立索引之前先将c://index目录清空。        IndexWriter writer new IndexWriter(c://index,new StandardAnalyzer(),true);                // 这个是数据源的文件夹        File file new File(c://file);        /* 例子主要是将C://file目录下的文件的内容进行建立索引将文件路径作为搜索内容的附属. */                      if(file.isDirectory())        {            String[] fileList file.list();             for (int i 0; i fileList.length; i)            {               //  建立一个新的文档,它可以看作是数据库的一行记录                Document doc new Document();                File f new File(file,                        fileList[i]);                Reader reader new BufferedReader(new FileReader(f));                doc.add(new Field(file,reader));//为doument添加field                doc.add(new Field(path,f.getAbsolutePath(),Field.Store.YES,Field.Index.NO));                writer.addDocument(doc);            }        }        writer.close();//这一步是必须的只有这样数据才会被写入索引的目录里        Date date2 new Date();        System.out.println(用时(date2.getTime()-date1.getTime())毫秒);} 注意因为建立索引本来就是费时所以说最后输出的用时会比较长请不要奇怪。 b)一个通过索引来全文检索的例子 public void HelloSearch() throws IOException, ParseException     {        IndexSearcher indexSearcher new IndexSearcher(c://index);//和上面的IndexWriter一样是一个工具        QueryParser queryParser new QueryParser(file,//这是一个分词器                new StandardAnalyzer());        BufferedReader br new BufferedReader(new InputStreamReader(System.in));        Query query queryParser.parse(br.readLine());//这个地方Query是抽象类大家也注意一下下面会讲到的        Hits hits indexSearcher.search(query);        Document doc null;        System.out.print(正搜索................);        for (int i 0; i hits.length(); i)        {            doc hits.doc(i);            System.out.println(内容是doc.get(file));//注意这里输出的是什么            System.out.println(文件的路径是 doc.get(path));        }    } 通过上面的两个例子应该可以看出Lucene还是比较简单的。运行一下上面的两个例子大家可能会说怎么doc.get(“file”);返回的是空呢,我们马上会讲到。   转载声明 本文转自 http://www.360doc.com/content/06/1229/01/16773_311395.shtml 360 doc   Lucene.Net 基本用法   本文仅记录一些简单的使用方法供初学者参考。以下例子采用 Lucene.NET 1.9 版本可取去 Lucene.Net 下载。1. 基本应用using System;using System.Collections.Generic;using System.Text;using Lucene.Net;using Lucene.Net.Analysis;using Lucene.Net.Analysis.Standard;using Lucene.Net.Documents;using Lucene.Net.Index;using Lucene.Net.QueryParsers;using Lucene.Net.Search;using Lucene.Net.Store;using Lucene.Net.Util;namespace ConsoleApplication1.Lucene{  public class LuceneTest  {    private const string FieldName name;    private const string FieldValue value;    private Directory directory new RAMDirectory();    private Analyzer analyzer new StandardAnalyzer();    public LuceneTest()    {    }    private void Index()    {      IndexWriter writer new IndexWriter(directory, analyzer, true);      writer.maxFieldLength 1000;            for (int i 1; i 100; i)      {        Document document new Document();        document.Add(new Field(FieldName, name i, Field.Store.YES, Field.Index.UN_TOKENIZED));        document.Add(new Field(FieldValue, Hello, World!, Field.Store.YES, Field.Index.TOKENIZED));        writer.AddDocument(document);      }      writer.Optimize();      writer.Close();    }    private void Search()    {      Query query QueryParser.Parse(name*, FieldName, analyzer);      IndexSearcher searcher new IndexSearcher(directory);      Hits hits searcher.Search(query);            Console.WriteLine(符合条件记录:{0}; 索引库记录总数:{1}, hits.Length(), searcher.Reader.NumDocs());      for (int i 0; i hits.Length(); i)      {        int docId hits.Id(i);        string name hits.Doc(i).Get(FieldName);        string value hits.Doc(i).Get(FieldValue);        float score hits.Score(i);        Console.WriteLine({0}: DocId:{1}; Name:{2}; Value:{3}; Score:{4},           i 1, docId, name, value, score);      }      searcher.Close();    }  }}除了 RAMDirectory还可以使用 FSDirectory。(注意 FSDirectory.GetDirectory 的 create 参数为 true 时将删除已有索引库文件可以通过 IndexReader.IndexExists() 方法判断。)从指定目录打开已有索引库。private Directory directory FSDirectory.GetDirectory(c:/index, false);将索引库载入内存以提高搜索速度。private Directory directory new RAMDirectory(FSDirectory.GetDirectory(c:/index, false));//或//private Directory directory new RAMDirectory(c:/index);2. 多字段搜索使用 MultiFieldQueryParser 可以指定多个搜索字段。Query query MultiFieldQueryParser.Parse(name*, new string[] { FieldName, FieldValue }, analyzer);IndexReader reader IndexReader.Open(directory);IndexSearcher searcher new IndexSearcher(reader);Hits hits searcher.Search(query);3. 多条件搜索除了使用 QueryParser.Parse 分解复杂的搜索语法外还可以通过组合多个 Query 来达到目的。Query query1 new TermQuery(new Term(FieldValue, name1)); // 词语搜索Query query2 new WildcardQuery(new Term(FieldName, name*)); // 通配符 //Query query3 new PrefixQuery(new Term(FieldName, name1)); // 字段搜索 Field:Keyword自动在结尾添加 *//Query query4 new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范围搜索//Query query5 new FilteredQuery(query, filter); // 带过滤条件的搜索      BooleanQuery query new BooleanQuery();query.Add(query1, BooleanClause.Occur.MUST);query.Add(query2, BooleanClause.Occur.MUST);IndexSearcher searcher new IndexSearcher(reader);Hits hits searcher.Search(query);4. 设置权重可以给 Document 和 Field 增加权重(Boost)使其在搜索结果排名更加靠前。缺省情况下搜索结果以 Document.Score 作为排序依据该数值越大排名越靠前。Boost 缺省值为 1。Score Score * Boost通过上面的公式我们就可以设置不同的权重来影响排名。如下面的例子中根据 VIP 级别设定不同的权重。Document document new Document();switch (vip){  case VIP.Gold: document.SetBoost(2F); break;  case VIP.Argentine: document.SetBoost(1.5F); break;}只要 Boost 足够大那么就可以让某个命中结果永远排第一位这就是百度等网站的收费排名业务。明显有失公平鄙视一把。  5. 排序通过 SortField 的构造参数我们可以设置排序字段排序条件以及倒排。Sort sort new Sort(new SortField(FieldName, SortField.DOC, false));IndexSearcher searcher new IndexSearcher(reader);Hits hits searcher.Search(query, sort);排序对搜索速度影响还是很大的尽可能不要使用多个排序条件。6. 过滤使用 Filter 对搜索结果进行过滤可以获得更小范围内更精确的结果。举个例子我们搜索上架时间在 2005-10-1 到 2005-10-30 之间的商品。对于日期时间我们需要转换一下才能添加到索引库同时还必须是索引字段。// indexdocument.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);//...// searchFilter filter new DateFilter(FieldDate, DateTime.Parse(2005-10-1), DateTime.Parse(2005-10-30));Hits hits searcher.Search(query, filter);除了日期时间还可以使用整数。比如搜索价格在 100 ~ 200 之间的商品。Lucene.Net NumberTools 对于数字进行了补位处理如果需要使用浮点数可以自己参考源码进行。// indexdocument.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));//...// searchFilter filter new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);Hits hits searcher.Search(query, filter);使用 Query 作为过滤条件。QueryFilter filter new QueryFilter(QueryParser.Parse(name2, FieldValue, analyzer));我们还可以使用 FilteredQuery 进行多条件过滤。Filter filter new DateFilter(FieldDate, DateTime.Parse(2005-10-10), DateTime.Parse(2005-10-15));Filter filter2 new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);Query query QueryParser.Parse(name*, FieldName, analyzer);query new FilteredQuery(query, filter);query new FilteredQuery(query, filter2);IndexSearcher searcher new IndexSearcher(reader);Hits hits searcher.Search(query);7. 分布搜索我们可以使用 MultiReader 或 MultiSearcher 搜索多个索引库。MultiReader reader new MultiReader(new IndexReader[] { IndexReader.Open(c:/index), IndexReader.Open(//server/index) });IndexSearcher searcher new IndexSearcher(reader);Hits hits searcher.Search(query);或IndexSearcher searcher1 new IndexSearcher(reader1);IndexSearcher searcher2 new IndexSearcher(reader2);MultiSearcher searcher new MultiSearcher(new Searchable[] { searcher1, searcher2 });Hits hits searcher.Search(query);还可以使用 ParallelMultiSearcher 进行多线程并行搜索。8. 合并索引库将 directory1 合并到 directory2 中。Directory directory1 FSDirectory.GetDirectory(index1, false);Directory directory2 FSDirectory.GetDirectory(index2, false);IndexWriter writer new IndexWriter(directory2, analyzer, false);writer.AddIndexes(new Directory[] { directory });Console.WriteLine(writer.DocCount());writer.Close();9. 显示搜索语法字符串我们组合了很多种搜索条件或许想看看与其对等的搜索语法串是什么样的。BooleanQuery query new BooleanQuery();query.Add(query1, true, false);query.Add(query2, true, false);//...Console.WriteLine(Syntax: {0}, query.ToString());输出Syntax: (name:name* value:name*) number:[0000000000000000b TO 0000000000000000d]呵呵就这么简单。10. 操作索引库删除 (软删除仅添加了删除标记。调用 IndexWriter.Optimize() 后真正删除。)IndexReader reader IndexReader.Open(directory);// 删除指定序号(DocId)的 Document。reader.Delete(123);// 删除包含指定 Term 的 Document。reader.Delete(new Term(FieldValue, Hello));// 恢复软删除。reader.UndeleteAll();reader.Close();增量更新 (只需将 create 参数设为 false即可往现有索引库添加新数据。)Directory directory FSDirectory.GetDirectory(index, false);IndexWriter writer new IndexWriter(directory, analyzer, false);writer.AddDocument(doc1);writer.AddDocument(doc2);writer.Optimize();writer.Close();11. 优化批量向 FSDirectory 增加索引时增大合并因子(mergeFactor )和最小文档合并数(minMergeDocs)有助于提高性能减少索引时间。IndexWriter writer new IndexWriter(directory, analyzer, true);writer.maxFieldLength 1000; // 字段最大长度writer.mergeFactor 1000;writer.minMergeDocs 1000;for (int i 0; i 10000; i){  // Add Documentes...}writer.Optimize();writer.Close();相关参数说明 转自《深入 Lucene 索引机制》利用 Lucene在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题, Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢幸运的是Lucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。1合并因子 (mergeFactor)这个参数决定了在 Lucene 的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如如果合并因子的值是 10那么当内存中的文档数达到 10 的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且如果磁盘上的索引块的隔数达到 10 的话这 10 个索引块会被合并成一个新的索引块。这个参数的默认值是 10如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲为这个参数赋一个比较大的值会得到比较好的索引效果。2最小合并文档数 (minMergeDocs)这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10如果你有足够的内存那么将这个值尽量设的比较大一些将会显著的提高索引性能。3最大合并文档数 (maxMergeDocs)这个参数决定了一个索引块中的最大的文档数。它的默认值是 Integer.MAX_VALUE将这个参数设置为比较大的值可以提高索引效率和检索速度由于该参数的默认值是整型的最大值所以我们一般不需要改动这个参数。-------------------迷糊中的分割线-----------------------------Lucene 相关资源1. Lucene 官方网站2. Apache Lucene3. Lucene FAQ4. Lucene.Net5. Lucene API (Java)6. DotLucene7. Luke - Lucene Index Toolbox8. Nutch9. LUCENE.COM.CN 中国10. Compass11. 实战 Lucene第 1 部分: 初识 Lucene12. 深入 Lucene 索引机制   转载声明 本文转自 http://www.rainsts.net/article.asp?id313 雨痕转载于:https://www.cnblogs.com/skybreak/archive/2013/05/06/3063520.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/82222.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商 wordpress主题河北网站seo策划

目录 一:绘制直线 二:绘制矩形 三:绘制圆形 四:绘制椭圆

网站空间选择公司介绍ppt制作

一、 总则 本部分规定了 IT 运维服务支撑系统的应用需求,包括 IT 运维服务模型与模式、 IT 运维服务管理体系、以及 IT 运维服务和管理能力评估与提升途径。 二、 参考标准 下列文件中的条款通过本部分的引用而成为本部分的条款。凡是注日期的引用文件&#xff0c…

中小企业网站建设开题报告网站购物车建设

笔记来源: 1.【传送门】 2.【传送门】 前沿原理介绍 Grander因果检验是一种分析时间序列数据因果关系的方法。 基本思想在于,在控制Y的滞后项 (过去值) 的情况下,如果X的滞后项仍然有助于解释Y的当期值的变动,则认为 X对 Y产生…

新增网站备案设计一个自己公司网站开发

在开发阶段,如果同时拥有多个开源代码托管平台的账户,在代码的管理上非常麻烦。那么,如果同一台机器上需要配置多个账户,怎样才能确保不冲突,不同账户独立下载独立提交呢? 我们以两个github账号进行演示 …

免费网站后台管理系统模板下载青岛网站建设信息公示

一、 1.1 QSqlRelationalTableModel继承自QSqlTableModel,并且对其进行了扩展,提供了对外键的支持。一个外键就是一个表中的一个字段 和 其他表中的主键字段之间的一对一的映射。例如,“studInfo”表中的departID字段对应的是“departments…

网站开发 如何定位学生免费服务器

DB-Engines 数据库流行度排行榜 10 月更新已发布,排名前二十如下:这期的数据比较有意思,到了这个月,Microsoft SQL Server 马上扭转局势,成了分数增长最多的一个,与上个月相比其增加了 9.66 分,…

公司网站建设合同需要交印花税教育机构做网站素材

首先来看看网上的一篇文章:http://it.dengchao.org/neatbeans-problem-fedora/linux/ 在Windows和Linux(Fedora/Ubuntu/RedHat)中安装了NetBeans后,会遇到菜单等显示乱码的问题。这里告诉大家如何解决中文显示乱码的问题,包括Windows、Fedor…

有引导页的网站网站移动端就是app吗

智能停车场物联网远程监控解决方案 智能停车场物联网远程监控解决方案是一种集成了现代物联网技术、大数据分析以及云计算等先进技术手段,对停车场进行全面智能化管理的综合系统。它通过实时感知、精准采集和高效传输各类停车数据,实现对停车场运营状态…

网站建设 天猫 保证金做网站需要虚拟主机还是服务器

1.数据字典(固定的数据,省市级有层级关系的) //mp表如果没有这个字段,防报错,eleUI需要这个字段TableField(exist false) //父根据id得到子数据 ,从controller开始自动生成代码-->service//hasChildren怎么判断,只需要判断children的parentid的count数量>0就可以了//优化…

凡科网站建设怎么去掉极速建站外省住房和城乡建设厅网站

阿丹: myisam存储引擎与innodb存储引擎战争,在mysql中5.5.5之前myisam还是mysql的默认存储引擎但是在5.5.5版本之后被innodb反超。 官方解释: MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM所改…

做淘宝这样的网站需要什么像wordpress一样的网站吗

算法马拉松24 A 小C的多边形 题意:n1个点的多边形。给外圈的边标记上1~n,里圈的边也标记上1~n,使得对于一个外圈相邻点与中间点构成的三角形的边权之和都相等。\(n \le 10^6\) 题解:显然每个三角形权值和为\(\frac{3(n1)}{2}\) 一…

在线教育类网站模板wordpress自定义登录界面

Linux软件安装解决方案 在linux中安装软件是一件并不算轻松的工作,有很多中解决方案供你选择,但需要的是你的一点点耐心与智慧!下面我将就Linux中最常见的安装方式,由浅入深的逐一做简单介绍与说明,希望可以给您带来帮…

杭州正晖建设工程有限公司网站网络营销事件案例

81.C中的组合和继承相比的优缺点 在C中组合一对象系用描述对象包对象系组一个拥对象例其变合类的含的现。这的量类当有员被创建。 以下一个示例,展示了在C中如何实现组合关系: class Engine {// Engine class definition... };class Car {Engine engi…

长沙做网站公司合肥网站建设司图

使用Rust有一段时间了,期间尝试过使用Rust做后端开发、命令行工具开发,以及做端侧模型部署,也尝试过交叉编译、FFI调用等,也算是基本入门了。在用Rust做后端接口开发时,常常会找不到一些合适库,而这些库在J…

家用电脑搭建网站广州市口碑好的网站制作排名

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.代码实现4.参考文献 1.背景 2020年,Chou 等人受到水母运动行为启发,提出了人工水母搜索算法(Artificial Jellyfish Search Optimizer, JS)。 2.算法原理 2.1算法思想 JS模拟了水母的搜索行为&#xf…

资源seo网站优化排名注册公司代理记账报税

C#.net使用npgsql批量写入数据入库到postgresql数据库 npgsql批量存储数据1. 单条存储2. 批量存储 npgsql批量存储数据 转载自:https://blog.csdn.net/liuwanying0226/article/details/130825503 1. 单条存储 当有类型限定时,例如jsonb,在…

国外网站建设费用南宁市优化网站

jdk只有一个java进程StackOverflow.com上一个普遍的问题是:“ Java程序如何获得自己的进程ID? 与该问题相关的几个答案包括解析ManagementFactory返回的String 。 getRuntimeMXBean() 。 getName() [但是可…

公司网站建设模板seo网站结构优化的方法

文章目录 一、974. 和可被 K 整除的子数组1.题目简介2.解题思路3.代码4.运行结果 二、525. 连续数组1.题目简介2.解题思路3.代码4.运行结果 三、560. 和为 K 的子数组1.题目简介2.解题思路3.代码4.运行结果 总结 一、974. 和可被 K 整除的子数组 1.题目简介 974. 和可被 K 整…

福州省建设局网站辽宁建设工程人才网

1.简述 1 牛顿法简介 牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。 多数方程不存…