如何使用字段值提升 hibernate-search 查询?
How to boost hibernate-search query with field values?
我在一个实体中有两个字段 class:
- 机构名称
- 联系人类型
contactType 的值类似于 PBX、GSM、TEL 和 FAX
我想要一个评分机制,以便首先获得最匹配的数据,然后是 PBX、TEL、GSM 和 FAX。
得分:
- 在establishmentName上先获取最匹配的数据
- 在 contactType 上获取第一个 PBX 然后 TEL 等等
我的最终查询是:
(+establishmentName:kamran~1^2.5 +(contactType:PBX^2.0 contactType:TEL^1.8 contactType:GSM^1.6 contactType:FAX^1.4))
但它没有return结果。
我的问题是,如何根据不同的值提升特定字段?
我们可以对两个不同的字段使用以下查询:
Query query = qb.keyword()
.onField( field_one).boostedTo(2.0f)
.andField( field_two)
.matching( searchTerm)
.createQuery();
但我需要提升一个字段的值,因为在我的例子中是 contactType。
我的数据集:
(establishmentName : Concert Decoration, contactType : GSM),
(establishmentName : Elissa Concert, contactType : TEL),
(establishmentName : Yara Concert, contactType : FAX),
(establishmentName : E Concept, contactType : TEL),
(establishmentName : Infinity Concept, contactType : FAX),
(establishmentName : SD Concept, contactType : PBX),
(establishmentName : Broadcom Technical Concept, contactType : GSM),
(establishmentName : Concept Businessmen, contactType : PBX)
通过搜索term=concert(对establishmentName的模糊查询),应该return我的列表如下:
(establishmentName : Elissa Concert, contactType : TEL)
[term=concert, exact matching so it will be on top by keeping the
order as PBX, TEL, GSM and FAX]
(establishmentName : Contact Decoration, contactType : GSM)
[term=concert, exact matching and by keeping the order as PBX, TEL,
GSM and FAX]
(establishmentName : Yara Concert, contactType : FAX)
[term=concert, exact matching and by keeping the order as PBX, TEL,
GSM and FAX]
(establishmentName : Concept Businessmen, contactType : PBX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM
and FAX]
(establishmentName : SD Concept, contactType : PBX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM
and FAX]
(establishmentName : E Concept, contactType : TEL)
[term=concert, partial matching and keeping the order as PBX, TEL,
GSM and FAX]
(establishmentName : Broadcom Technical Concept, contactType : GSM)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM
and FAX]
(establishmentName : Infinity Concept, contactType : FAX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM
and FAX]
据我了解,您基本上需要两阶段排序:
- 将完全匹配放在其他(模糊)匹配之前。
- 按联系人类型排序。
第二种是微不足道的,但第一种需要一些工作。
其实可以靠评分来实现。
基本上这个想法是 运行 多个查询的分离,并为每个查询分配一个常量分数。
而不是这样做:
Query query = qb.keyword()
.fuzzy().withEditDistanceUpTo(1)
.boostedTo(2.5f)
.onField("establishmentName")
.matching(searchTerm)
.createQuery();
这样做:
Query query = qb.bool()
.should(qb.keyword()
.withConstantScore().boostedTo(100.0f) // Higher score, sort first
.onField("establishmentName")
.matching(searchTerm)
.createQuery())
.should(qb.keyword()
.fuzzy().withEditDistanceUpTo(1)
.withConstantScore().boostedTo(1.0f) // Lower score, sort last
.onField("establishmentName")
.matching(searchTerm)
.createQuery())
.createQuery();
匹配的文档将相同,但是现在查询将分配可预测的分数:1.0 用于仅模糊匹配,101.0(1 来自模糊查询,100 来自精确查询)以获得完全匹配。
这样,您可以定义排序如下:
fullTextQuery.setSort(qb.sort()
.byScore()
.andByField("contactType")
.createSort());
这可能不是一个非常优雅或优化的解决方案,但我认为它会起作用。
要自定义联系人类型的相对顺序,我建议采用不同的方法:使用 custom bridge 来索引号码而不是 "PBX"/"TEL"/等,分配为每个联系人键入您期望的序号。本质上是这样的:
public class Establishment {
@Field(name = "contactType_sort", bridge = @FieldBridge(impl = ContactTypeOrdinalBridge.class))
private ContactType contactType;
}
public class ContactTypeOrdinalBridge implements MetadataProvidingFieldBridge {
@Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
if ( value != null ) {
int ordinal = getOrdinal((ContactType) value);
luceneOptions.addNumericFieldToDocument(name, ordinal, document);
luceneOptions.addNumericDocValuesFieldToDocument(name, ordinal, document);
}
}
@Override
public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
builder.field(name, FieldType.INTEGER).sortable(true);
}
private int getOrdinal(ContactType value) {
switch( value ) {
case PBX: return 0;
case TEL: return 1;
case GSM: return 2;
case PBX: return 3;
default: return 4;
}
}
}
然后重新索引,并像这样排序:
fullTextQuery.setSort(qb.sort()
.byScore()
.andByField("contactType_sort")
.createSort());
我在一个实体中有两个字段 class:
- 机构名称
- 联系人类型
contactType 的值类似于 PBX、GSM、TEL 和 FAX
我想要一个评分机制,以便首先获得最匹配的数据,然后是 PBX、TEL、GSM 和 FAX。
得分:
- 在establishmentName上先获取最匹配的数据
- 在 contactType 上获取第一个 PBX 然后 TEL 等等
我的最终查询是:
(+establishmentName:kamran~1^2.5 +(contactType:PBX^2.0 contactType:TEL^1.8 contactType:GSM^1.6 contactType:FAX^1.4))
但它没有return结果。
我的问题是,如何根据不同的值提升特定字段?
我们可以对两个不同的字段使用以下查询:
Query query = qb.keyword()
.onField( field_one).boostedTo(2.0f)
.andField( field_two)
.matching( searchTerm)
.createQuery();
但我需要提升一个字段的值,因为在我的例子中是 contactType。
我的数据集:
(establishmentName : Concert Decoration, contactType : GSM),
(establishmentName : Elissa Concert, contactType : TEL),
(establishmentName : Yara Concert, contactType : FAX),
(establishmentName : E Concept, contactType : TEL),
(establishmentName : Infinity Concept, contactType : FAX),
(establishmentName : SD Concept, contactType : PBX),
(establishmentName : Broadcom Technical Concept, contactType : GSM),
(establishmentName : Concept Businessmen, contactType : PBX)
通过搜索term=concert(对establishmentName的模糊查询),应该return我的列表如下: (establishmentName : Elissa Concert, contactType : TEL)
[term=concert, exact matching so it will be on top by keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : Contact Decoration, contactType : GSM)
[term=concert, exact matching and by keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : Yara Concert, contactType : FAX)
[term=concert, exact matching and by keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : Concept Businessmen, contactType : PBX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : SD Concept, contactType : PBX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : E Concept, contactType : TEL)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : Broadcom Technical Concept, contactType : GSM)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM and FAX]
(establishmentName : Infinity Concept, contactType : FAX)
[term=concert, partial matching and keeping the order as PBX, TEL, GSM and FAX]
据我了解,您基本上需要两阶段排序:
- 将完全匹配放在其他(模糊)匹配之前。
- 按联系人类型排序。
第二种是微不足道的,但第一种需要一些工作。 其实可以靠评分来实现。
基本上这个想法是 运行 多个查询的分离,并为每个查询分配一个常量分数。
而不是这样做:
Query query = qb.keyword()
.fuzzy().withEditDistanceUpTo(1)
.boostedTo(2.5f)
.onField("establishmentName")
.matching(searchTerm)
.createQuery();
这样做:
Query query = qb.bool()
.should(qb.keyword()
.withConstantScore().boostedTo(100.0f) // Higher score, sort first
.onField("establishmentName")
.matching(searchTerm)
.createQuery())
.should(qb.keyword()
.fuzzy().withEditDistanceUpTo(1)
.withConstantScore().boostedTo(1.0f) // Lower score, sort last
.onField("establishmentName")
.matching(searchTerm)
.createQuery())
.createQuery();
匹配的文档将相同,但是现在查询将分配可预测的分数:1.0 用于仅模糊匹配,101.0(1 来自模糊查询,100 来自精确查询)以获得完全匹配。
这样,您可以定义排序如下:
fullTextQuery.setSort(qb.sort()
.byScore()
.andByField("contactType")
.createSort());
这可能不是一个非常优雅或优化的解决方案,但我认为它会起作用。
要自定义联系人类型的相对顺序,我建议采用不同的方法:使用 custom bridge 来索引号码而不是 "PBX"/"TEL"/等,分配为每个联系人键入您期望的序号。本质上是这样的:
public class Establishment {
@Field(name = "contactType_sort", bridge = @FieldBridge(impl = ContactTypeOrdinalBridge.class))
private ContactType contactType;
}
public class ContactTypeOrdinalBridge implements MetadataProvidingFieldBridge {
@Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
if ( value != null ) {
int ordinal = getOrdinal((ContactType) value);
luceneOptions.addNumericFieldToDocument(name, ordinal, document);
luceneOptions.addNumericDocValuesFieldToDocument(name, ordinal, document);
}
}
@Override
public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
builder.field(name, FieldType.INTEGER).sortable(true);
}
private int getOrdinal(ContactType value) {
switch( value ) {
case PBX: return 0;
case TEL: return 1;
case GSM: return 2;
case PBX: return 3;
default: return 4;
}
}
}
然后重新索引,并像这样排序:
fullTextQuery.setSort(qb.sort()
.byScore()
.andByField("contactType_sort")
.createSort());