一、Feild域
1.Field域的属性
是否分词:Tokenized
是:对该field存储的内容进行分词,分词的目的,就是为了索引。
否:不需要对field存储的内容进行分词,不分词,不代表不索引,而是将整个内容进行索引。
是否索引:Indexed
是:将分好的词进行索引,索引的目的,就是为了搜索。
否:不索引,也就是不对该field域进行搜索。
是否存储:Stored
是:将field域中的内容存储到文档域中。存储的目的,就是为了搜索页面显示取值用的。
否:不将field域中的内容存储到文档域中。不存储,则搜索页面中没法获取该field域的值。
2.常用Field:
Field类 |
数据类型 |
Analyzed 是否分词 |
Indexed 是否索引 |
Stored 是否存储 |
说明 |
StringField(FieldName, FieldValue,Store.YES)) |
字符串 |
N |
Y |
Y或N |
这个Field用来构建一个字符串Field,但是不会进行分词,会将整个串存储在索引中,比如(订单号,身份证号等) 是否存储在文档中用Store.YES或Store.NO决定 |
LongField(FieldName, FieldValue,Store.YES) |
Long型 |
Y |
Y |
Y或N |
这个Field用来构建一个Long数字型Field,进行分词和索引,比如(价格) 是否存储在文档中用Store.YES或Store.NO决定 |
StoredField(FieldName, FieldValue) |
重载方法,支持多种类型 |
N |
N |
Y |
这个Field用来构建不同类型Field 不分析,不索引,但要Field存储在文档中 |
TextField(FieldName, FieldValue, Store.NO) 或 TextField(FieldName, reader) |
字符串 或 流 |
Y |
Y |
Y或N |
如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略. |
完整类图如下:
按照这个改造入门程序的Field的用法:
// 创建文档中的Field域,Store可以确定是否存储到文档域中
// ID,使用StringField;分词:否;索引:是;存储:是
Field idField = new StringField("id", book.getId().toString(), Field.Store.YES);
// name 使用TextField;分词:是;索引:是;存储:是
Field nameField = new TextField("name", book.getName(), Field.Store.YES);
// price 使用FloatField;分词:是;索引:是;存储:是
Field priceField = new FloatField("price", book.getPrice(), Field.Store.YES);
// pic 不分词不索引,但存储
Field picField = new StoredField("pic", book.getPic());
// description 分词索引不存储
Field descriptionField = new TextField("description", book.getDescription(), Field.Store.NO);
然后删掉索引,重新生成一下索引
二、索引的维护
包含索引的 增删改等维护操作
1.增加索引:
调用 indexWriter.addDocument(doc)添加索引。
//参考入门程序
2.删除索引:
根据Term删除:Term是索引库中的最小单位,也就是索引结构图索引域的 组成部分。
// 删除索引
@Test
public void deleteIndex() throws Exception {
// 1、指定索引库目录
Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));
// 2、创建IndexWriterConfig
IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
new StandardAnalyzer());
// 3、 创建IndexWriter
IndexWriter writer = new IndexWriter(directory, cfg);
// 4、通过IndexWriter来删除索引
// b)、删除指定索引
writer.deleteDocuments(new Term("filename", "apache"));
// 5、关闭IndexWriter
writer.close();
}
//删除的是一个document对象,也就是类似数据库删除一条记录,根据id删除也就相当于SQL中delById()
想要删除全部:
writer.deleteAll();
3.修改索引
需要先查后改,需要先找到需要修改的索引,再提供新的值即可
// 修改索引
@Test
public void updateIndex() throws Exception {
// 1、指定索引库目录
Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));
// 2、创建IndexWriterConfig
IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,
new StandardAnalyzer());
// 3、 创建IndexWriter
IndexWriter writer = new IndexWriter(directory, cfg);
// 4、通过IndexWriter来修改索引
// a)、创建修改后的文档对象
Document document = new Document(); // 文件名称
Field filenameField = new StringField("filename", "updateIndex", Store.YES);
document.add(filenameField); // 修改指定索引为新的索引
writer.updateDocument(new Term("filename", "apache"), document); // 5、关闭IndexWriter
writer.close();
}
//若未查询到结果,则直接新增
三、搜索
1.通过Query子类来创建查询对象
Query子类常用的有:TermQuery、NumericRangeQuery、BooleanQuery
TermQuery——精确的词项查询
Query query = new TermQuery(new Term("name", "lucene"))
package com.itheima.lucene.first; import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test; /**
*
* <p>
* Title: IndexSearch
* </p>
*
* <p>
* Description: TODO(这里用一句话描述这个类的作用)
* <p>
* <p>
* Company: www.itcast.com
* </p>
* @author 传智.关云长 @date 2015-12-27 上午11:05:35 @version 1.0
*/
public class IndexSearch { private void doSearch(Query query) {
// 创建IndexSearcher
// 指定索引库的地址
try {
File indexFile = new File("E:\\11-index\\hm19\\");
Directory directory = FSDirectory.open(indexFile);
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
// 通过searcher来搜索索引库
// 第二个参数:指定需要显示的顶部记录的N条
TopDocs topDocs = searcher.search(query, 10); // 根据查询条件匹配出的记录总数
int count = topDocs.totalHits;
System.out.println("匹配出的记录总数:" + count);
// 根据查询条件匹配出的记录
ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档的ID
int docId = scoreDoc.doc; // 通过ID获取文档
Document doc = searcher.doc(docId);
System.out.println("商品ID:" + doc.get("id"));
System.out.println("商品名称:" + doc.get("name"));
System.out.println("商品价格:" + doc.get("price"));
System.out.println("商品图片地址:" + doc.get("pic"));
System.out.println("==========================");
// System.out.println("商品描述:" + doc.get("description"));
}
// 关闭资源
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void indexSearch() throws Exception {
// 创建query对象
// 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
// 第一个参数:默认搜索的域的名称
QueryParser parser = new QueryParser("description",
new StandardAnalyzer()); // 通过queryparser来创建query对象
// 参数:输入的lucene的查询语句(关键字一定要大写)
Query query = parser.parse("description:java AND lucene"); doSearch(query); } @Test
public void termQuery() {
// 创建TermQuery对象
Query query = new TermQuery(new Term("description", "java")); doSearch(query);
} @Test
public void numericRangeQuery() { // 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); doSearch(query);
} @Test
public void booleanQuery() {
// 创建BooleanQuery
BooleanQuery query = new BooleanQuery();
// 创建TermQuery对象
Query q1 = new TermQuery(new Term("description", "lucene"));
// 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query q2 = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); // 组合关系代表的意思如下:
// 1、MUST和MUST表示“与”的关系,即“交集”。
// 2、MUST和MUST_NOT前者包含后者不包含。
// 3、MUST_NOT和MUST_NOT没意义
// 4、SHOULD与MUST表示MUST,SHOULD失去意义;
// 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。
// 6、SHOULD与SHOULD表示“或”的概念。 query.add(q1, Occur.MUST_NOT);
query.add(q2, Occur.MUST_NOT); doSearch(query);
} @Test
public void multiFieldQueryParser() throws Exception {
// 创建7.3.2 MultiFieldQueryParser
// 默认搜索的多个域的域名
String[] fields = { "name", "description" };
Analyzer analyzer = new StandardAnalyzer();
Map<String, Float> boosts = new HashMap<String, Float>();
boosts.put("name", 200f);
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields,
analyzer, boosts); // Query query = parser.parse("name:lucene OR description:lucene");
Query query = parser.parse("java"); System.out.println(query); doSearch(query);
}
}
NumericRangeQuery——数字范围查询
Query query = NumericRangeQuery.newLongRange("size", 1l, 100l, true,true);
package com.itheima.lucene.first; import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test; /**
*
* <p>
* Title: IndexSearch
* </p>
*
* <p>
* Description: TODO(这里用一句话描述这个类的作用)
* <p>
* <p>
* Company: www.itcast.com
* </p>
* @author 传智.关云长 @date 2015-12-27 上午11:05:35 @version 1.0
*/
public class IndexSearch { private void doSearch(Query query) {
// 创建IndexSearcher
// 指定索引库的地址
try {
File indexFile = new File("E:\\11-index\\hm19\\");
Directory directory = FSDirectory.open(indexFile);
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
// 通过searcher来搜索索引库
// 第二个参数:指定需要显示的顶部记录的N条
TopDocs topDocs = searcher.search(query, 10); // 根据查询条件匹配出的记录总数
int count = topDocs.totalHits;
System.out.println("匹配出的记录总数:" + count);
// 根据查询条件匹配出的记录
ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档的ID
int docId = scoreDoc.doc; // 通过ID获取文档
Document doc = searcher.doc(docId);
System.out.println("商品ID:" + doc.get("id"));
System.out.println("商品名称:" + doc.get("name"));
System.out.println("商品价格:" + doc.get("price"));
System.out.println("商品图片地址:" + doc.get("pic"));
System.out.println("==========================");
// System.out.println("商品描述:" + doc.get("description"));
}
// 关闭资源
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void indexSearch() throws Exception {
// 创建query对象
// 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
// 第一个参数:默认搜索的域的名称
QueryParser parser = new QueryParser("description",
new StandardAnalyzer()); // 通过queryparser来创建query对象
// 参数:输入的lucene的查询语句(关键字一定要大写)
Query query = parser.parse("description:java AND lucene"); doSearch(query); } @Test
public void termQuery() {
// 创建TermQuery对象
Query query = new TermQuery(new Term("description", "java")); doSearch(query);
} @Test
public void numericRangeQuery() { // 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); doSearch(query);
} @Test
public void booleanQuery() {
// 创建BooleanQuery
BooleanQuery query = new BooleanQuery();
// 创建TermQuery对象
Query q1 = new TermQuery(new Term("description", "lucene"));
// 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query q2 = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); // 组合关系代表的意思如下:
// 1、MUST和MUST表示“与”的关系,即“交集”。
// 2、MUST和MUST_NOT前者包含后者不包含。
// 3、MUST_NOT和MUST_NOT没意义
// 4、SHOULD与MUST表示MUST,SHOULD失去意义;
// 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。
// 6、SHOULD与SHOULD表示“或”的概念。 query.add(q1, Occur.MUST_NOT);
query.add(q2, Occur.MUST_NOT); doSearch(query);
} @Test
public void multiFieldQueryParser() throws Exception {
// 创建7.3.2 MultiFieldQueryParser
// 默认搜索的多个域的域名
String[] fields = { "name", "description" };
Analyzer analyzer = new StandardAnalyzer();
Map<String, Float> boosts = new HashMap<String, Float>();
boosts.put("name", 200f);
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields,
analyzer, boosts); // Query query = parser.parse("name:lucene OR description:lucene");
Query query = parser.parse("java"); System.out.println(query); doSearch(query);
}
}
BooleanQuery——布尔查询,实现组合条件查询。
BooleanQuery query = new BooleanQuery();
Query query1 = new TermQuery(new Term("id", "3"));
Query query2 = NumericRangeQuery.newFloatRange("price", 10f, 200f,
true, true); //MUST:查询条件必须满足,相当于AND
//SHOULD:查询条件可选,相当于OR
//MUST_NOT:查询条件不能满足,相当于NOT非
query.add(query1, Occur.MUST);
query.add(query2, Occur.SHOULD); System.out.println(query);
package com.itheima.lucene.first; import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test; /**
*
* <p>
* Title: IndexSearch
* </p>
*
* <p>
* Description: TODO(这里用一句话描述这个类的作用)
* <p>
* <p>
* Company: www.itcast.com
* </p>
* @author 传智.关云长 @date 2015-12-27 上午11:05:35 @version 1.0
*/
public class IndexSearch { private void doSearch(Query query) {
// 创建IndexSearcher
// 指定索引库的地址
try {
File indexFile = new File("E:\\11-index\\hm19\\");
Directory directory = FSDirectory.open(indexFile);
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
// 通过searcher来搜索索引库
// 第二个参数:指定需要显示的顶部记录的N条
TopDocs topDocs = searcher.search(query, 10); // 根据查询条件匹配出的记录总数
int count = topDocs.totalHits;
System.out.println("匹配出的记录总数:" + count);
// 根据查询条件匹配出的记录
ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档的ID
int docId = scoreDoc.doc; // 通过ID获取文档
Document doc = searcher.doc(docId);
System.out.println("商品ID:" + doc.get("id"));
System.out.println("商品名称:" + doc.get("name"));
System.out.println("商品价格:" + doc.get("price"));
System.out.println("商品图片地址:" + doc.get("pic"));
System.out.println("==========================");
// System.out.println("商品描述:" + doc.get("description"));
}
// 关闭资源
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void indexSearch() throws Exception {
// 创建query对象
// 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
// 第一个参数:默认搜索的域的名称
QueryParser parser = new QueryParser("description",
new StandardAnalyzer()); // 通过queryparser来创建query对象
// 参数:输入的lucene的查询语句(关键字一定要大写)
Query query = parser.parse("description:java AND lucene"); doSearch(query); } @Test
public void termQuery() {
// 创建TermQuery对象
Query query = new TermQuery(new Term("description", "java")); doSearch(query);
} @Test
public void numericRangeQuery() { // 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); doSearch(query);
} @Test
public void booleanQuery() {
// 创建BooleanQuery
BooleanQuery query = new BooleanQuery();
// 创建TermQuery对象
Query q1 = new TermQuery(new Term("description", "lucene"));
// 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query q2 = NumericRangeQuery.newFloatRange("price", 55f, 60f, true,
false); // 组合关系代表的意思如下:
// 1、MUST和MUST表示“与”的关系,即“交集”。
// 2、MUST和MUST_NOT前者包含后者不包含。
// 3、MUST_NOT和MUST_NOT没意义
// 4、SHOULD与MUST表示MUST,SHOULD失去意义;
// 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。
// 6、SHOULD与SHOULD表示“或”的概念。 query.add(q1, Occur.MUST_NOT);
query.add(q2, Occur.MUST_NOT); doSearch(query);
} @Test
public void multiFieldQueryParser() throws Exception {
// 创建7.3.2 MultiFieldQueryParser
// 默认搜索的多个域的域名
String[] fields = { "name", "description" };
Analyzer analyzer = new StandardAnalyzer();
Map<String, Float> boosts = new HashMap<String, Float>();
boosts.put("name", 200f);
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields,
analyzer, boosts); // Query query = parser.parse("name:lucene OR description:lucene");
Query query = parser.parse("java"); System.out.println(query); doSearch(query);
}
}
2.通过QueryParser来创建查询对象
QueryParser(可以使用lucene语法,常用)、MultiFieldQueryParser
QueryParser
通过QueryParser也可以创建Query,QueryParser提供一个Parse方法,此方法可以直接根据查询语法来查询。Query对象执行的查询语法可通过System.out.println(query);查询。
示例:
@Test
public void testQueryParser() throws Exception {
// 创建QueryParser
// 第一个参数:默认域名
// 第二个参数:分词器
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
// 指定查询语法 ,如果不指定域,就搜索默认的域
Query query = queryParser.parse("lucene");
System.out.println(query);
// 2、 执行搜索
doSearch(query); }
MultiFieldQueryParser——多域查询
@Test
public void testMultiFieldQueryParser() throws Exception {
// 可以指定默认搜索的域是多个
String[] fields = { "name", "description" };
// 创建一个MulitFiledQueryParser对象
QueryParser parser = new MultiFieldQueryParser(fields, new IKAnalyzer());
// 指定查询语法 ,如果不指定域,就搜索默认的域
Query query = parser.parse("lucene");
// 2、 执行搜索
doSearch(query);
}
3.查询语法
1.基础查询语法
域名+“:”+搜索的关键字
例如:content:java
2.范围查询
域名+“:”+[最小值 TO 最大值]
例如:size:[1 TO 1000]
//注意:QueryParser不支持对数字范围的搜索,它支持字符串范围。数字范围搜索建议使用NumericRangeQuery。
3.条件查询
1)+条件1 +条件2:两个条件之间是并且的关系and
例如:+filename:apache +content:apache
2)+条件1 条件2:必须满足第一个条件,忽略第二个条件
例如:+filename:apache content:apache
3)条件1 条件2:两个条件满足其一即可。
例如:filename:apache content:apache
4)-条件1 条件2:必须不满足条件1,要满足条件2
例如:-filename:apache content:apache
4.TopDocs
Search方法需要指定匹配记录数量n:indexSearcher.search(query, n)
TopDocs.totalHits:是匹配索引库中所有记录的数量
TopDocs.scoreDocs:匹配相关度高的前边记录数组,scoreDocs的长度小于等于search方法指定的参数n
四、相关度排序
1.什么是相关度
相关度排序是查询结果按照与查询关键字的相关性进行排序,越相关的越靠前。比如搜索“Lucene”关键字,与该关键字最相关的文章应该排在前边。
2.相关度打分
Lucene对查询关键字和索引文档的相关度进行打分,得分高的就排在前边。如何打分呢?Lucene是在用户进行检索时实时根据搜索的关键字计算出来的,分两步:
1)计算出词(Term)的权重
2)根据词的权重值,计算文档相关度得分
什么是词的权重?
通过索引部分的学习,明确索引的最小单位是一个Term(索引词典中的一个词),搜索也是要从Term中搜索,再根据Term找到文档,Term对文档的重要性称为权重,影响Term权重有两个因素:
Tf
词在同一个文档中出现的频率
Tf越高,说明词的权重越高
Df
词在多个文档中出现的频率
Df越高,说明词的权重越低
以上是自然打分的规则。
3.设置boost值影响打分
Boost:加权值,默认是1.0f。
设置加权值可以在创建索引时设置,也可以在查询时设置。
Boost值是设置到Field域上的。
1.创建时指定(常用)
@Test
public void setBoost4createIndex() throws Exception {
// 创建分词器
Analyzer analyzer = new StandardAnalyzer(); IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_4_10_3,
analyzer);
Directory directory = FSDirectory.open(new File("E:\\11-index\\0728"));
// 创建IndexWriter对象,通过它把分好的词写到索引库中
IndexWriter writer = new IndexWriter(directory, cfg); Document doc = new Document();
Field id = new StringField("id", "11", Store.YES);
Field description = new TextField("description", "测试设置BOOST值 lucene",
Store.YES);
// 设置boost
description.setBoost(10.0f);
// 把域添加到文档中
doc.add(id);
doc.add(description);
writer.addDocument(doc);
// 关闭IndexWriter
writer.close();
}
2..在MultiFieldQueryParser创建时设置boost值。
五、中文分词器
1.什么是中文分词器
学过英文的都知道,英文是以单词为单位的,单词与单词之间以空格或者逗号句号隔开。而中文则以字为单位,字又组成词,字和词再组成句子。所以对于英文,我们可以简单以空格判断某个字符串是否为一个单词,
比如I love China,love 和 China很容易被程序区分开来;但中文“我爱中国”就不一样了,电脑不知道“中国”是一个词语还是“爱中”是一个词语。把中文的句子切分成有意义的词,就是中文分词,也称切词。我爱中国,分词的结果是:我 爱 中国。
2.Lucene自带分词器
StandardAnalyzer:
单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。
CJKAnalyzer
二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。
3.第三方中文分词器
这里暂时只介绍实际使用的: IKAnalyzer
其它例如 smartcn等暂时不展开。
如何使用:
相关的使用步骤可以参见:http://blog.csdn.net/cyxlzzs/article/details/7999212
1.添加jar
2.修改分词器:
// 创建中文分词器
Analyzer analyzer = new IKAnalyzer();
3.从ikanalyzer包中拷贝配置文件到classpath下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties> <comment>IK Analyzer 扩展配置</comment>
<!-- 用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">dicdata/mydict.dic</entry>
<!-- 用户可以在这里配置自己的扩展停用词字典 -->
<entry key="ext_stopwords">dicdata/ext_stopword.dic</entry> </properties>
如果想配置扩展词和停用词,就创建扩展词的文件和停用词的文件,文件的编码要是utf-8。
注意:不要用记事本保存扩展词文件和停用词文件,那样的话,格式中是含有bom的。(使用IDE或者Editplus)
添加扩展词文件:ext.dic,内容如下: