Java Hibernate搜索排序与排序
我将Hibernate搜索从版本-4.3.0.Final升级到最新的稳定版本-5.4.12.Final。除了对挪威语进行分类外,一切都很好。在旧版本的hibernate中,构造函数中存在带有区域设置的SortField:Java Hibernate搜索排序与排序,java,lucene,hibernate-search,Java,Lucene,Hibernate Search,我将Hibernate搜索从版本-4.3.0.Final升级到最新的稳定版本-5.4.12.Final。除了对挪威语进行分类外,一切都很好。在旧版本的hibernate中,构造函数中存在带有区域设置的SortField: /** Creates a sort, possibly in reverse, by terms in the given field sorted * according to the given locale. * @param field Name of
/** Creates a sort, possibly in reverse, by terms in the given field sorted
* according to the given locale.
* @param field Name of field to sort by, cannot be <code>null</code>.
* @param locale Locale of values in the field.
*/
public SortField (String field, Locale locale, boolean reverse) {
initFieldType(field, STRING);
this.locale = locale;
this.reverse = reverse;
}
但是在新的hibernate搜索中,SortField没有区域设置。根据hibernate参考文档()对外语中的单词进行排序,我们应该使用带有normalizer的CollationKeyFilterFactory。但是在这个版本的hibernate搜索中没有这样的类。Maven pom:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.11.5.Final</version>
</dependency>
非常类似的问题,没有答案:我不确定它对您有多大帮助,但
排序规则KeyFilterFactory
已被弃用并确实被删除
在类的Javadoc中,它表示:
已弃用。改用
CollationKeyAnalyzer
您可以找到。我不确定它对您有多大帮助,但
CollationKeyFilterFactory
已被弃用并确实被删除
在类的Javadoc中,它表示:
已弃用。改用
CollationKeyAnalyzer
你可以找到那个
但是在这个版本的hibernate搜索中没有这样的类
文档的这一部分看起来过时了,我将研究更新它
我发现了CollationKeyAnalyzer
,但是javadoc声明它已经过时,应该改用ICUCollationKeyAnalyzer
尝试将此依赖项添加到POM:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>5.5.5</version>
</dependency>
然后创建您的字段:
@实体
@索引
公共类MyEntity{
// ...
@字段(name=“title\u sort”,index=index.NO,normalizer=@normalizer(impl=myCallationKeyAnalyzer.class))
@可排序字段(forField=“title\u sort”)
私有字符串标题;
// ...
}
然后按如下方式对该字段进行排序:
FullTextEntityManager ftEm=Search.getFullTextEntityManager(entityManager);
QueryBuilder qb=…;//照常
查询luceneQuery=…;//照常
FullTextQuery-ftQuery=ftEm.createFullTextQuery(luceneQuery,MyEntity.class);
ftQuery.setSort(qb.sort().byField(“title_sort”).createSort());
ftQuery.setMaxResults(20);
List hits=ftQuery.getResultList();
我没有试过这个,所以让我们知道它是否对你有用
但是在这个版本的hibernate搜索中没有这样的类
文档的这一部分看起来过时了,我将研究更新它
我发现了CollationKeyAnalyzer
,但是javadoc声明它已经过时,应该改用ICUCollationKeyAnalyzer
尝试将此依赖项添加到POM:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>5.5.5</version>
</dependency>
然后创建您的字段:
@实体
@索引
公共类MyEntity{
// ...
@字段(name=“title\u sort”,index=index.NO,normalizer=@normalizer(impl=myCallationKeyAnalyzer.class))
@可排序字段(forField=“title\u sort”)
私有字符串标题;
// ...
}
然后按如下方式对该字段进行排序:
FullTextEntityManager ftEm=Search.getFullTextEntityManager(entityManager);
QueryBuilder qb=…;//照常
查询luceneQuery=…;//照常
FullTextQuery-ftQuery=ftEm.createFullTextQuery(luceneQuery,MyEntity.class);
ftQuery.setSort(qb.sort().byField(“title_sort”).createSort());
ftQuery.setMaxResults(20);
List hits=ftQuery.getResultList();
不过我没有尝试过,所以请告诉我们它是否对您有效。为了解决排序问题,我创建了自己的挪威安装工厂。这不是一个完美的解决方案,因为我从Hibernate Search的旧版本(IndexableBinaryStringTools.class)复制了代码,但它运行良好。
挪威安装工厂等级:
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import java.text.Collator;
import java.util.Locale;
import java.util.Map;
public final class NorwegianCollationFactory extends TokenFilterFactory {
public NorwegianCollationFactory(Map<String, String> args) {
super(args);
}
@Override
public TokenStream create(TokenStream input) {
Collator norwegianCollator = Collator.getInstance(new Locale("no", "NO"));
return new CollationKeyFilter(input, norwegianCollator);
}
}
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import java.io.IOException;
import java.text.Collator;
import java.util.Objects;
public final class CollationKeyFilter extends TokenFilter {
// This code is copied from IndexableBinaryStringTools.class from the old version of hibernate search 4.3.0.Final
private static final CollationKeyFilter.CodingCase[] CODING_CASES = {
new CollationKeyFilter.CodingCase(7, 1),
new CollationKeyFilter.CodingCase(14, 6, 2),
new CollationKeyFilter.CodingCase(13, 5, 3),
new CollationKeyFilter.CodingCase(12, 4, 4),
new CollationKeyFilter.CodingCase(11, 3, 5),
new CollationKeyFilter.CodingCase(10, 2, 6),
new CollationKeyFilter.CodingCase(9, 1, 7),
new CollationKeyFilter.CodingCase(8, 0)
};
private final Collator collator;
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
public CollationKeyFilter(TokenStream input, Collator collator) {
super(input);
this.collator = (Collator) collator.clone();
}
@Override
public boolean incrementToken() throws IOException {
if (input.incrementToken()) {
byte[] collationKey = collator.getCollationKey(termAtt.toString()).toByteArray();
int encodedLength = getBinaryStringEncodedLength(collationKey.length);
termAtt.resizeBuffer(encodedLength);
termAtt.setLength(encodedLength);
encodeToBinaryString(collationKey, collationKey.length, termAtt.buffer());
return true;
} else {
return false;
}
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private void encodeToBinaryString(byte[] inputArray, int inputLength, char[] outputArray) {
if (inputLength > 0) {
int inputByteNum = 0;
int caseNum = 0;
int outputCharNum = 0;
CollationKeyFilter.CodingCase codingCase;
for (; inputByteNum + CODING_CASES[caseNum].numBytes <= inputLength; ++outputCharNum) {
codingCase = CODING_CASES[caseNum];
if (codingCase.numBytes == 2) {
outputArray[outputCharNum] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ (((inputArray[inputByteNum + 1] & 0xFF) >>> codingCase.finalShift) & codingCase.finalMask) & (short) 0x7FFF);
} else {
outputArray[outputCharNum] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift)
+ (((inputArray[inputByteNum + 2] & 0xFF) >>> codingCase.finalShift) & codingCase.finalMask) & (short) 0x7FFF);
}
inputByteNum += codingCase.advanceBytes;
if (++caseNum == CODING_CASES.length) {
caseNum = 0;
}
}
codingCase = CODING_CASES[caseNum];
if (inputByteNum + 1 < inputLength) {
outputArray[outputCharNum++] = (char) ((((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift)) & (short) 0x7FFF);
outputArray[outputCharNum] = (char) 1;
} else if (inputByteNum < inputLength) {
outputArray[outputCharNum++] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift) & (short) 0x7FFF);
outputArray[outputCharNum] = caseNum == 0 ? (char) 1 : (char) 0;
} else {
outputArray[outputCharNum] = (char) 1;
}
}
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private int getBinaryStringEncodedLength(int inputLength) {
return (int) ((8L * inputLength + 14L) / 15L) + 1;
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private static class CodingCase {
int numBytes;
int initialShift;
int middleShift;
int finalShift;
int advanceBytes = 2;
short middleMask;
short finalMask;
CodingCase(int initialShift, int middleShift, int finalShift) {
this.numBytes = 3;
this.initialShift = initialShift;
this.middleShift = middleShift;
this.finalShift = finalShift;
this.finalMask = (short) ((short) 0xFF >>> finalShift);
this.middleMask = (short) ((short) 0xFF << middleShift);
}
CodingCase(int initialShift, int finalShift) {
this.numBytes = 2;
this.initialShift = initialShift;
this.finalShift = finalShift;
this.finalMask = (short) ((short) 0xFF >>> finalShift);
if (finalShift != 0) {
advanceBytes = 1;
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
CollationKeyFilter that = (CollationKeyFilter) o;
return Objects.equals(collator, that.collator) &&
Objects.equals(termAtt, that.termAtt);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), collator, termAtt);
}
}
为了解决排序问题,我创建了自己的挪威振动工厂。这不是一个完美的解决方案,因为我从Hibernate Search的旧版本(IndexableBinaryStringTools.class)复制了代码,但它运行良好。
挪威安装工厂等级:
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.util.TokenFilterFactory;
import java.text.Collator;
import java.util.Locale;
import java.util.Map;
public final class NorwegianCollationFactory extends TokenFilterFactory {
public NorwegianCollationFactory(Map<String, String> args) {
super(args);
}
@Override
public TokenStream create(TokenStream input) {
Collator norwegianCollator = Collator.getInstance(new Locale("no", "NO"));
return new CollationKeyFilter(input, norwegianCollator);
}
}
import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import java.io.IOException;
import java.text.Collator;
import java.util.Objects;
public final class CollationKeyFilter extends TokenFilter {
// This code is copied from IndexableBinaryStringTools.class from the old version of hibernate search 4.3.0.Final
private static final CollationKeyFilter.CodingCase[] CODING_CASES = {
new CollationKeyFilter.CodingCase(7, 1),
new CollationKeyFilter.CodingCase(14, 6, 2),
new CollationKeyFilter.CodingCase(13, 5, 3),
new CollationKeyFilter.CodingCase(12, 4, 4),
new CollationKeyFilter.CodingCase(11, 3, 5),
new CollationKeyFilter.CodingCase(10, 2, 6),
new CollationKeyFilter.CodingCase(9, 1, 7),
new CollationKeyFilter.CodingCase(8, 0)
};
private final Collator collator;
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
public CollationKeyFilter(TokenStream input, Collator collator) {
super(input);
this.collator = (Collator) collator.clone();
}
@Override
public boolean incrementToken() throws IOException {
if (input.incrementToken()) {
byte[] collationKey = collator.getCollationKey(termAtt.toString()).toByteArray();
int encodedLength = getBinaryStringEncodedLength(collationKey.length);
termAtt.resizeBuffer(encodedLength);
termAtt.setLength(encodedLength);
encodeToBinaryString(collationKey, collationKey.length, termAtt.buffer());
return true;
} else {
return false;
}
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private void encodeToBinaryString(byte[] inputArray, int inputLength, char[] outputArray) {
if (inputLength > 0) {
int inputByteNum = 0;
int caseNum = 0;
int outputCharNum = 0;
CollationKeyFilter.CodingCase codingCase;
for (; inputByteNum + CODING_CASES[caseNum].numBytes <= inputLength; ++outputCharNum) {
codingCase = CODING_CASES[caseNum];
if (codingCase.numBytes == 2) {
outputArray[outputCharNum] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ (((inputArray[inputByteNum + 1] & 0xFF) >>> codingCase.finalShift) & codingCase.finalMask) & (short) 0x7FFF);
} else {
outputArray[outputCharNum] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift)
+ (((inputArray[inputByteNum + 2] & 0xFF) >>> codingCase.finalShift) & codingCase.finalMask) & (short) 0x7FFF);
}
inputByteNum += codingCase.advanceBytes;
if (++caseNum == CODING_CASES.length) {
caseNum = 0;
}
}
codingCase = CODING_CASES[caseNum];
if (inputByteNum + 1 < inputLength) {
outputArray[outputCharNum++] = (char) ((((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift)
+ ((inputArray[inputByteNum + 1] & 0xFF) << codingCase.middleShift)) & (short) 0x7FFF);
outputArray[outputCharNum] = (char) 1;
} else if (inputByteNum < inputLength) {
outputArray[outputCharNum++] = (char) (((inputArray[inputByteNum] & 0xFF) << codingCase.initialShift) & (short) 0x7FFF);
outputArray[outputCharNum] = caseNum == 0 ? (char) 1 : (char) 0;
} else {
outputArray[outputCharNum] = (char) 1;
}
}
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private int getBinaryStringEncodedLength(int inputLength) {
return (int) ((8L * inputLength + 14L) / 15L) + 1;
}
// This code is copied from IndexableBinaryStringTools class from the old version of hibernate search 4.3.0.Final
private static class CodingCase {
int numBytes;
int initialShift;
int middleShift;
int finalShift;
int advanceBytes = 2;
short middleMask;
short finalMask;
CodingCase(int initialShift, int middleShift, int finalShift) {
this.numBytes = 3;
this.initialShift = initialShift;
this.middleShift = middleShift;
this.finalShift = finalShift;
this.finalMask = (short) ((short) 0xFF >>> finalShift);
this.middleMask = (short) ((short) 0xFF << middleShift);
}
CodingCase(int initialShift, int finalShift) {
this.numBytes = 2;
this.initialShift = initialShift;
this.finalShift = finalShift;
this.finalMask = (short) ((short) 0xFF >>> finalShift);
if (finalShift != 0) {
advanceBytes = 1;
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
CollationKeyFilter that = (CollationKeyFilter) o;
return Objects.equals(collator, that.collator) &&
Objects.equals(termAtt, that.termAtt);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), collator, termAtt);
}
}
ICUCollationKeyAnalyzer是最终版本,无法扩展。您可以将代码从
ICUCollationKeyAnalyzer
复制到您的类中,这非常简单。我更新了答案。ICUCollationKeyAnalyzer是最终版本,无法扩展。您可以将代码从ICUCollationKeyAnalyzer
复制到您的类中,这非常简单。我更新了答案。