上一篇:Lucene基础(1)

一、Lucene术语

Document, Field, Term, Query, Analyzer相信在其中大多数在之前已经理解了...对其中部分概念详细说明

Document是一个包含了多个Field的容器,通过以下代码应该容易理解二者的关系

  Document document=new Document();
//Field.Store.YES或者NO(存储域选项)
//设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
//设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
for(int i=0;i<ids.length;i++){
document.add(new StringField("ids",ids[i], Field.Store.YES));
document.add(new StringField("names",names[i], Field.Store.YES));
document.add(new TextField("describes",describes[i], Field.Store.YES));
indexWriter.addDocument(document);
}

Field的一般构造器:

protected Field(String name, FieldType type)

下面说明常见的FieldType

http://lucene.apache.org/core/5_5_3/core/org/apache/lucene/document/FieldType.html

(1) NumbericType

public enum NumericType {
/** 32-bit integer numeric type */
INT,
/** 64-bit long numeric type */
LONG,
/** 32-bit float numeric type */
FLOAT,
/** 64-bit double numeric type */
DOUBLE
}

如果是数值类型,可以通过NumbericType来指明

(2) Stored

private boolean stored;

是否存储field的值。如果true,原始的字符串值全部被保存在索引中,并可以由IndexReader类恢复。该选项对于需要展示搜索结果的一些域很有用(如URL,标题等)。如果为false,则索引中不存储field的值,通常用来索引大的文本域值。如Web页面的正文

(3) tokenized

 private boolean tokenized = true;

是否使用分析器将域值分解成独立的语汇单元流。该属性仅当indexed()为true时有效.

(4) 加权相关

  • private boolean storeTermVectors;当lucene建立起倒排索引后,默认情况下它会保存所有必要的信息实施Vector Space Model。该Model需要计算文档中出现的term数,以及他们出现的位置。该属性仅当indexed为true时生效。他会为field建立一个小型的倒排索引。
  • private boolean storeTermVectorOffsets;表示是否存储field的token character的偏移量到 term vectors向量中。
  • private boolean storeTermVectorPositions;表示是否存储field中token的位置到term vectors 向量中。
  • private boolean storeTermVectorPayloads;是否存储field中token的比重到term vectors中。
  • private boolean omitNorms;是否要忽略field的加权基准值,如果为true可以节省内存消耗,但在打分质量方面会有更高的消耗,另外你也不能使用index-time 进行加权操作。

(5) IndexOptions

// NOTE: order is important here; FieldInfo uses this
// order to merge two conflicting IndexOptions (always
// "downgrades" by picking the lowest).
/** Not indexed */
NONE,
/**
* Only documents are indexed: term frequencies and positions are omitted.
* Phrase and other positional queries on the field will throw an exception, and scoring
* will behave as if any term in the document appears only once.
*/
DOCS,
/**
* Only documents and term frequencies are indexed: positions are omitted.
* This enables normal scoring, except Phrase and other positional queries
* will throw an exception.
*/
DOCS_AND_FREQS,
/**
* Indexes documents, frequencies and positions.
* This is a typical default for full-text search: full scoring is enabled
* and positional queries are supported.
*/
DOCS_AND_FREQS_AND_POSITIONS,
/**
* Indexes documents, frequencies, positions and offsets.
* Character offsets are encoded alongside the positions.
*/
DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS,

说明如下:

  • DOCS_ONLY:仅documents被索引,term的频率和位置都将被忽略。针对field的短语或有关位置的查询都将抛出异常。
  • DOCS_AND_FREQS:documents和term的频率被索引,term的位置被忽略。这样可以正常打分,但针对field的短语或有关位置的查询都将抛出异常。
  • DOCS_AND_FREQS_AND_POSITIONS:这是一个全文检索的默认设置,打分和位置检索都支持。
  • DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS:索引字符相对位置的偏移量。

(6) DocValueType

/**
* No doc values for this field.
*/
NONE,
/**
* A per-document Number
*/
NUMERIC,
/**
* A per-document byte[]. Values may be larger than
* 32766 bytes, but different codecs may enforce their own limits.
*/
BINARY,
/**
* A pre-sorted byte[]. Fields with this type only store distinct byte values
* and store an additional offset pointer per document to dereference the shared
* byte[]. The stored byte[] is presorted and allows access via document id,
* ordinal and by-value. Values must be {@code <= 32766} bytes.
*/
SORTED,
/**
* A pre-sorted Number[]. Fields with this type store numeric values in sorted
* order according to {@link Long#compare(long, long)}.
*/
SORTED_NUMERIC,
/**
* A pre-sorted Set&lt;byte[]&gt;. Fields with this type only store distinct byte values
* and store additional offset pointers per document to dereference the shared
* byte[]s. The stored byte[] is presorted and allows access via document id,
* ordinal and by-value. Values must be {@code <= 32766} bytes.
*/
SORTED_SET,

如果非空,field的值将被索引成docValues.

  • NUMERIC:数字类型
  • BINARY:二进制类型
  • SORTED:只保存不同的二进制值 byte[]
  • SORTED_SET.

(7) frozen

阻止field属性未来可能的变更,该属性通常在FieldType 属性已经被设置后调用。是为了防止无意识的变更

二、增删改查演示

原文链接:http://www.kailing.pub/index/columns/colid/16.html

public class IndexerCRUD {
//测试数据,模拟数据库表结构
private static String[] ids={"1","2","3"}; //用户ID
private static String [] names={"kl","wn","sb"};
private static String [] describes={"shi yi ge mei nan zi","Don't know","Is an idiot\n"};
//索引存储地址
private static String indexDir="G:\\projects-helloworld\\lucene\\src\\main\\resources\\LuceneIndex";
/**
* 获取操作索引实体,并添加测试数据
* @param indexDir 索引存储位置
* @return
* @throws Exception
*/
public static IndexWriter getIndexWriter(String indexDir)throws Exception{
IndexWriterConfig writerConfig=new IndexWriterConfig(getAnalyzer());
IndexWriter indexWriter=new IndexWriter(getDirectory(indexDir),writerConfig);
Document document=new Document();
//Field.Store.YES或者NO(存储域选项)
//设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
//设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
for(int i=0;i<ids.length;i++){
document.add(new StringField("ids",ids[i], Field.Store.YES));
document.add(new StringField("names",names[i], Field.Store.YES));
document.add(new TextField("describes",describes[i], Field.Store.YES));
indexWriter.addDocument(document);
}
return indexWriter;
}
/**
* 得到默认分词器
* @return
*/
public static Analyzer getAnalyzer(){
return new StandardAnalyzer();
}
/**
* 得到索引磁盘存储器
* @param indexDir 存储位置
* @return
*/
public static Directory getDirectory(String indexDir){
Directory directory=null;
try {
directory= FSDirectory.open(Paths.get(indexDir));
}catch (Exception e){
e.printStackTrace();
}
return directory;
}
/**
* 获取读索引实体,并打印读到的索引信息
* @return
*/
public static IndexReader getIndexReader(){
IndexReader reader=null;
try {
reader= DirectoryReader.open(getDirectory(indexDir));
//通过reader可以有效的获取到文档的数量
System.out.println("当前存储的文档数::"+reader.numDocs());
System.out.println("当前存储的文档数,包含回收站的文档::"+reader.maxDoc());
System.out.println("回收站的文档数:"+reader.numDeletedDocs()); } catch (Exception e) {
e.printStackTrace();
}
return reader;
} /**
* 写索引测试,借助Luke观察结果
* @throws Exception
*/
@Test
public void Testinsert() throws Exception{
IndexWriter writer=getIndexWriter(indexDir);
writer.close();
getIndexReader();
}
/**
* 删除索引测试,借助Luke观察结果
* @throws Exception
*/
public void TestDelete()throws Exception{
//测试删除前我们先把上次的索引文件删掉,或者换个目录
IndexWriter writer=getIndexWriter(indexDir);
QueryParser parser=new QueryParser("ids", getAnalyzer());//指定Document的某个属性
Query query=parser.parse("2");//指定索引内容,对应某个分词
Term term=new Term("names","kl");
//参数是一个选项,可以是一个query,也可以是一个term,term是一个精确查找的值
writer.deleteDocuments(query);//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
writer.forceMergeDeletes();//强制合并删除的索引信息,索引量大的时候不推荐使用,真正的删除
// writer.commit(); //更改索引要提交,和提交数据库事务一个概念,真正的删除
writer.close();
getIndexReader();
}
/**
* 更新操作测试,借助Luke观察结果
* @throws Exception
*/
public void TestUpdate()throws Exception{
// Lucene并没有提供更新,这里的更新操作相当于新增,他并不会去掉原来的信息
IndexWriter writer = getIndexWriter(indexDir);
try {
Document doc = new Document();
doc.add(new StringField("id","1",Field.Store.YES));
doc.add(new StringField("names","ckl",Field.Store.YES));
doc.add(new StringField("describes","chenkailing",Field.Store.NO));
writer.updateDocument(new Term("id","1"), doc); } catch (Exception e) {
e.printStackTrace();
} finally {
if(writer!=null) writer.close();
}
}
/**
* 查询测试
*/
@Test
public void TestSearchaer(){
try {
IndexReader reader = getIndexReader();
IndexSearcher searcher = new IndexSearcher(reader);
QueryParser parser=new QueryParser("names", getAnalyzer());//指定Document的某个属性
Query query=parser.parse("kl");//指定索引内容,对应某个分词
Term term=new Term("names","kl");
//参数是一个选项,可以是一个query,也可以是一个term,term是一个精确查找的值
TopDocs hits = searcher.search(query, 10);
for(ScoreDoc sd:hits.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println(
doc.get("names")+"["+doc.get("describes")+"]-->"+doc.get("ids"));
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}

三、常见Query用法

Query 是一个用于查询的抽象基类。搜索指定单词或词组涉及到在项中包装它们,将项添加到查询对象,将查询对象传递到 IndexSearcher 的搜索方法。

Lucene 包含各种类型的具体查询实现,比如 TermQuery、BooleanQuery、PhraseQuery、PrefixQuery、RangeQuery、MultiTermQuery、FilteredQuery、SpanQuery 等。以下部分讨论 Lucene 查询 API 的主查询类。

Basic: QueryParser和ScoreDoc

QueryParser 对于解析人工输入的查询字符非常有用。您可以使用它将用户输入的查询表达式解析为 Lucene 查询对象,这些对象可以传递到 IndexSearcher 的搜索方法。它可以解析丰富的查询表达式。 QueryParser 内部将人们输入的查询字符串转换为一个具体的查询子类。您需要使用反斜杠(\)将 *、? 等特殊字符进行转义。您可以使用运算符 AND、OR 和 NOT 构建文本布尔值查询。

QueryParser queryParser = new QueryParser("subject",new StandardAnalyzer());
// Search for emails that contain the words 'job openings' and '.net' and 'pune'
Query query = queryParser.parse("job openings AND .net AND pune");

indexSearcher 返回一组对分级搜索结果(如匹配给定查询的文档)的引用。您可以使用 IndexSearcher 的搜索方法确定需要检索的最优先搜索结果数量。可以在此基础上构建定制分页。您可以添加定制 Web 应用程序或桌面应用程序来显示搜索结果。检索搜索结果涉及的主要类包括 ScoreDoc 和 TopDocs。

ScoreDoc: 搜索结果中包含一个指向文档的简单指针。这可以封装文档索引中文档的位置以及 Lucene 计算的分数。 
封装搜索结果以及 ScoreDoc 的总数。 
以下代码片段展示了如何检索搜索结果中包含的文档。

/* First parameter is the query to be executed and
second parameter indicates the no of search results to fetch */
TopDocs topDocs = indexSearcher.search(query,20);
System.out.println(“Total hits “+topDocs.totalHits); // Get an array of references to matched documents
ScoreDoc[] scoreDosArray = topDocs.scoreDocs;
for(ScoreDoc scoredoc: scoreDosArray){
//Retrieve the matched document and show relevant details
  Document doc = indexSearcher.doc(scoredoc.doc);
  System.out.println(“\nSender: “+doc.getField(“sender”).stringValue());
  System.out.println(“Subject: “+doc.getField(“subject”).stringValue());
  System.out.println(“Email file location: ” +doc.getField(“emailDoc”).stringValue());
}

3.1 TermQuery

搜索索引最基本的查询类型。可以使用单个项构建TermQuery。项值应该区分大小写,但也并非全是如此。注意,传递的搜索项应该与文档分析得到的项一致,因为分析程序在构建索引之前对原文本执行许多操作。 
例如,考虑电子邮件标题 “Job openings for Java Professionals at Bangalore”。假设您使用 StandardAnalyzer 编制索引。现在如果我们使用 TermQuery 搜索 “Java”,它不会返回任何内容,因为本文本应该已经规范化,并通过 StandardAnalyzer 转成小写。如果搜索小写单词 “java”,它将返回所有标题字段中包含该单词的邮件。

//Search mails having the word "java" in the subject field
Searcher indexSearcher = new IndexSearcher(indexDirectory);
Term term = new Term("subject","java");
Query termQuery = new TermQuery(term);
TopDocs topDocs = indexSearcher.search(termQuery,10);

3.2 RangeQuery

您可以使用 RangeQuery 在某个范围内搜索。索引中的所有项都以字典顺序排列。Lucene 的 RangeQuery 允许用户在某个范围内搜索项。该范围可以使用起始项和最终项(包含两端或不包含两端均可)指定。

/* RangeQuery example:Search mails from 01/06/2009 to 6/06/2009
both inclusive */
Term begin = new Term("date","20090601");
Term end = new Term("date","20090606");
Query query = new RangeQuery(begin, end, true);

3.3 PrefixQuery

您可以使用 PrefixQuery 通过前缀单词进行搜索,该方法用于构建一个查询,该查询查找包含以指定单词前缀开始的词汇的文档。

//Search mails having sender field prefixed by the word 'job'
PrefixQuery prefixQuery = new PrefixQuery(new Term("sender","job"));
PrefixQuery query = new PrefixQuery(new Term("sender","job"));

3.4 BooleanQuery

您可以使用 BooleanQuery 组合任何数量的查询对象,构建强大的查询。它使用 query 和一个关联查询的子句,指示查询是应该发生、必须发生还是不得发生。在 BooleanQuery 中,子句的最大数量默认限制为 1,024。您可以调用 setMaxClauseCount 方法设置最大子句数。

// Search mails have both 'java' and 'bangalore' in the subject field
Query query1 = new TermQuery(new Term("subject","java"));
Query query2 = new TermQuery(new Term("subject","bangalore"));
BooleanQuery query = new BooleanQuery();
query.add(query1,BooleanClause.Occur.MUST);
query.add(query2,BooleanClause.Occur.MUST);

3.5 PhraseQuery

您可以使用 PhraseQuery 进行短语搜索。PhraseQuery 匹配包含特定单词序列的文档。PhraseQuery 使用索引中存储的项的位置信息。考虑匹配的项之间的距离称为 slop。默认情况下,slop 的值为零,这可以通过调用 setSlop 方法进行设置。PhraseQuery 还支持多个项短语。

/* PhraseQuery example: Search mails that have phrase 'job opening j2ee'
in the subject field.*/
PhraseQuery query = new PhraseQuery();
query.setSlop(1);
query.add(new Term("subject","job"));
query.add(new Term("subject","opening"));
query.add(new Term("subject","j2ee"));

3.6 WildcardQuery

WildcardQuery 实现通配符搜索查询,这允许您搜索 arch*(可以查找包含 architect、architecture 等)之类的单词。使用两个标准通配符: 
* 表示零个以上 
? 表示一个以上 
如果使用以通配符查询开始的模式进行搜索,则可能会引起性能的降低,因为这需要查询索引中的所有项以查找匹配文档。

//Search for 'arch*' to find e-mail messages that have word 'architect' in the subject
field./
Query query = new WildcardQuery(new Term("subject","arch*"));

3.7 FuzzyQuery

您可以使用 FuzzyQuery 搜索类似项,该类匹配类似于指定单词的单词。类似度测量基于 Levenshtein(编辑距离)算法进行。在列表 9 中,FuzzyQuery 用于查找与拼错的单词 “admnistrtor” 最接近的项,尽管这个错误单词没有索引。

/* Search for emails that have word similar to 'admnistrtor' in the
subject field. Note we have misspelled admnistrtor here.*/
Query query = new FuzzyQuery(new Term("subject", "admnistrtor"));

Lucene基础(2)的更多相关文章

  1. Lucene基础(1)

    下一篇: Lucene基础(2) 一.Lucene介绍 http://www.kailing.pub/index/columns/colid/16.html Documentation:http:// ...

  2. [全文检索]Lucene基础入门.

    本打算直接来学习Solr, 现在先把Lucene的只是捋一遍. 本文内容: 1. 搜索引擎的发展史 2. Lucene入门 3. Lucene的API详解 4. 索引调优 5. Lucene搜索结果排 ...

  3. Lucene基础学习笔记

    在学校和老师一起做项目,在老师的推荐下深入学习了一些SqlServer的知识,看一些书下来哎也没记住多少,不过带来了新疑问. 不使用模糊查询,我应该用什么呢?如何能不影响数据库性能,还能做模糊查询呢? ...

  4. JAVAEE——Lucene基础:什么是全文检索、Lucene实现全文检索的流程、配置开发环境、索引库创建与管理

    1. 学习计划 第一天:Lucene的基础知识 1.案例分析:什么是全文检索,如何实现全文检索 2.Lucene实现全文检索的流程 a) 创建索引 b) 查询索引 3.配置开发环境 4.创建索引库 5 ...

  5. 01 lucene基础 北风网项目培训 Lucene实践课程 系统架构

    Lucene在搜索的时候数据源可以是文件系统,数据库,web等等. Lucene的搜索是基于索引,Lucene是基于前面建立的索引之上进行搜索的. 使用Lucene就像使用普通的数据库一样. Luce ...

  6. lucene 基础知识点

    部分知识点的梳理,参考<lucene实战>及网络资料 1.基本概念 lucence 可以认为分为两大组件: 1)索引组件 a.内容获取:即将原始的内容材料,可以是数据库.网站(爬虫).文本 ...

  7. Lucene基础(一)--入门

    Lucene介绍 lucene的介绍,这里引用百度百科的介绍Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引 ...

  8. Lucene基础(二)--索引的操作

    索引的操作 我们建立所有就是要达到快速检索的目的,对数据能够方面便的查找,和数据库类似,索引也有自己的相关增删改查的操作. 在索引的增删改查中,增删改属于写操作,主要是有IndexWrite提供的方法 ...

  9. Lucene基础(三)-- 中文分词及高亮显示

    Lucene分词器及高亮 分词器 在lucene中我们按照分词方式把文档进行索引,不同的分词器索引的效果不太一样,之前的例子使用的都是标准分词器,对于英文的效果很好,但是中文分词效果就不怎么样,他会按 ...

随机推荐

  1. linux重要命令

    echo echo命令用于在终端显示字符串或输出变量提取后的值,格式为:"echo [字符串 | $变量]". 将指定字符串输出到终端屏幕: [root@linuxprobe ~] ...

  2. Python学习笔记——进阶篇【第九周】———MYSQL操作

    Mysql 增删改查操作 查看数据库 show databases; 创建数据库并允许中文插入 create database s12day9 charset utf8; 使用数据库 use s12d ...

  3. SQL Server2012中的SequenceNumber

    http://www.cnblogs.com/CareySon/archive/2012/03/12/2391581.html https://q.cnblogs.com/q/53552/ https ...

  4. iOSAPP添加启动页

    如果你在开发过程中出现屏幕显示内容比例不正常或者显示不全的问题,你发现不是代码或者约束的问题,那么很可能是启动页没有添加或者添加不全的原因,下面配一张问题图片上下黑屏 添加启动页步骤如下图 (1) ( ...

  5. javsscript总结

  6. 向多个会话窗口发送命令 -SecureCRT

    1.前提 一个服务可能部署在多台机器上,这时如果要查问题,最繁复的方法就是打开该服务的每个session,把命令在每一台机器上复制一下执行,找到相关的日志:还有一种方法就是一条命令同时向多个会话窗口发 ...

  7. Oracle SQL自带函数整理

    数字函数 abs(n):用于返回数字n的绝对值 ceil(n):返回大于等于数字n的最小整数 floor(n):返回小于等于数字n的最大整数 mod(m,n):返回m/n数字相除后的余数,如果n=0, ...

  8. Java处理JPEG图片时,需要导入com.sun.image.codec.jpeg.JPEGImageEn,报错处理

    Java处理JPEG图片时,需要导入com.sun.image.codec.jpeg.JPEGImageEn,会报错,不能使用相应的方法. 原因:java访问限制级api的时候,默认的eclipse设 ...

  9. c# 配置文件App.config操作类库

    public class ConfigOperator { #region 从配置文件获取Value /// <summary> /// 从配置文件获取Value /// </sum ...

  10. java中异常处理机制的简单原理

    以上是自认为的java异常处理的简单原理,如有不妥之处还请各位大神帮忙指点,谢谢!