用户的需求是多种多样的。比如:
现在,来介绍几种lucene的高级检索方式,来帮助我们满足各种各样的用户需求~~
用户在搜索引擎中进行搜索时,常常查找的并非是一个简单的单词,很有可能是几个不同的关键字。这些关键字之间要么是紧密相联,成为一个精确的短语,要么是可能在这几个关键字之间还插有其他无关的关键字。此时,用户希望将它们找出来。不过很显然,从评分的角度看,这些关键字之间拥有与查找内容无关短语所在的文档的分值一般会较低一些。
PhraseQuery正是Lucene所提供的满足上述需求的一种Query对象。它可以让用户往其内部添加关键字,在添加完毕后,用户还可以通过设置slop参数来设定一个称之为“坡度”的变量来确定关键字之间是否允许、允许多少个无关词汇的存在。
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class testPhraseQuery {
public static Version luceneVersion = Version.LATEST;
public static void indexSearch(){
DirectoryReader reader = null;
try{
Directory directory = FSDirectory.open(Paths.get("index3"));
reader= DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
Term t1=new Term("key2","孙悟空");
Term t2=new Term("key2","猪八戒");
//slop,term...;slop represents the maximum distance between the given terms.reference:
//http://lucene.apache.org/core/6_2_1/core/org/apache/lucene/search/PhraseQuery.html
PhraseQuery query=new PhraseQuery(5,"key2",t1.bytes(),t2.bytes());
String ss=query.toString();
System.out.println(ss);
TopDocs tds = searcher.search(query, 20);
ScoreDoc[] sds = tds.scoreDocs;
int cou=0;
for(ScoreDoc sd:sds){
cou++;
Document d = searcher.doc(sd.doc);
String output=cou+". "+d.get("category2")+"\n"+d.get("skey1")+"\n"+d.get("skey2");
System.out.println(output);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
indexSearch();
}
}
PhraseQuery的构造方法有四种:文档。这里介绍演示代码的构造方法:
PhraseQuery(int slop, String field, BytesRef... terms)
slop是int型,通过设置slop“坡度”来确定关键字之间是否允许、允许多少个无关词汇的存在。
filed是String,是要搜索的域。
terms是ByteRef,是用户要搜索的关键字。
因此,第一个需求可以使用PhraseQuery来满足。
RangeQuery是对字符串进行范围查询的,索引中的所有项都以字典顺序排列。它允许用户在某个范围内搜索,该范围的起始项和最终项都可以指定包含或不包含。
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class testRangeQuery {
public static Version luceneVersion = Version.LATEST;
public static void indexSearch(){
DirectoryReader reader = null;
try{
Directory directory = FSDirectory.open(Paths.get("indexrangequery"));
reader= DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
//*************测试一*******************
// Term begin = new Term("birthday","19980101");
// Term end = new Term("birthday","20040606");
// Query query = new TermRangeQuery("birthday",begin.bytes(),end.bytes(),false,false);
//*************测试二*******************
Term begin = new Term("lex","ab");
Term end = new Term("lex","cd");
Query query = new TermRangeQuery("lex",begin.bytes(),end.bytes(),false,false);
String ss=query.toString();
System.out.println(ss);
TopDocs tds = searcher.search(query, 20);
ScoreDoc[] sds = tds.scoreDocs;
System.out.println(sds.length);
int cou=0;
for(ScoreDoc sd:sds)
{
cou++;
Document d = searcher.doc(sd.doc);
String output=cou+". "+d.get("sname")+" "+d.get("sbirthday")+" "+d.get("sid")+" "+d.get("slex");
System.out.println(output);
}
}catch(Exception e){
e.printStackTrace();
}finally{
//9、关闭reader
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
indexSearch();
}
}
构造方法如下:
TermRangeQuery(String field, BytesRef lowerTerm, BytesRef upperTerm, boolean includeLower, boolean includeUpper)
field指明搜索的域;lowerTerm个upperTerm分别的起始项和最终项,最后两个boolean指定是开区间还是闭区间。
这样,对于用户第二个需求,就轻松解决了~~
FuzzyQuery是模糊匹配,基于编辑距离(Edit Distance)的Damerau-Levenshtein算法,编辑距离就是两个字符串有一个转变成另一个所需要的最小的操作步骤。
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class testFuzzyQuery {
public static Version luceneVersion = Version.LATEST;
public static void indexSearch(String keywords){
DirectoryReader reader = null;
try{
Directory directory = FSDirectory.open(Paths.get("index3"));
reader= DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
FuzzyQuery query=new FuzzyQuery(new Term("key1",keywords));
String ss=query.toString();
System.out.println(ss);
TopDocs tds = searcher.search(query, 20);
ScoreDoc[] sds = tds.scoreDocs;
int cou=0;
for(ScoreDoc sd:sds){
cou++;
Document d = searcher.doc(sd.doc);
String output=cou+". "+d.get("category2")+"\n"+d.get("skey1");
System.out.println(output);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
String keywords[]={"流星","眼睛","小学生"};
for(int i=0;i<keywords.length;i++)
{
indexSearch(keywords[i]);
}
}
}
该函数有四个构造方法,参加FuzzyQuery文档。关于FuzzyQuery的构造方法,这篇博客讲得很好:Lucene5学习之FuzzyQuery使用。
WildCardQuery是通配符查询,通配符“?”代表1个字符,而“*”则代表0至多个字符。使用方法很简单:
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class testWildCardQuery {
public static Version luceneVersion = Version.LATEST;
public static void indexSearch(String keywords){
DirectoryReader reader = null;
try{
Directory directory = FSDirectory.open(Paths.get("index3"));
reader= DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
WildcardQuery query=new WildcardQuery(new Term("key1",keywords));
String ss=query.toString();
System.out.println(ss);
TopDocs tds = searcher.search(query, 20);
ScoreDoc[] sds = tds.scoreDocs;
int cou=0;
for(ScoreDoc sd:sds){
cou++;
Document d = searcher.doc(sd.doc);
String output=cou+". "+d.get("category2")+"\n"+d.get("skey1");
System.out.println(output);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
String keywords[]={"流?雨","星*","小学*"};
for(int i=0;i<keywords.length;i++)
{
indexSearch(keywords[i]);
}
}
}
具体用法参考文档:WildCardQuery文档。
WildCardQuery和FuzzyQuery由于需要对字段关键字进行字符串匹配,所以,在搜索的性能上面会受到一些影响。
PrefixQuery用于匹配其索引开始以指定的字符串的文档。用法很简单:
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class testPrefixQuery {
public static Version luceneVersion = Version.LATEST;
public static void indexSearch(){
DirectoryReader reader = null;
try{
Directory directory = FSDirectory.open(Paths.get("index3"));
reader= DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
PrefixQuery query=new PrefixQuery(new Term("key1","中"));
String ss=query.toString();
System.out.println(ss);
TopDocs tds = searcher.search(query, 20);
ScoreDoc[] sds = tds.scoreDocs;
System.out.println(sds.length);
int cou=0;
for(ScoreDoc sd:sds){
cou++;
Document d = searcher.doc(sd.doc);
String output=cou+". "+d.get("category2")+"\n"+d.get("skey1")+"\n"+d.get("skey2");
System.out.println(output);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException
{
indexSearch();
}
}
详细说明参考官方文档:PrefixQuery文档。
上面的FuzzyQuery,WildCardQuery和PrefixQuery都是不精确查询,可以解决用户的第三个需求~~
https://blog.xqlee.com/article/2504291640282818.html