我正在开发一个项目,我正在使用Hibernate 5,它运行良好。现在,我要完成的是集成Hibernate Search,以便我可以通过它们的一些String类型属性来查找对象。顺便说一句,我是Hibernate Search的新手。
好消息是这个项目非常简单,因为只包含两个类:ParadaWS和OperadorWS。这些是类:
ParadaWS 上课:
package model.paradasws;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.FieldBridge;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import com.vividsolutions.jts.geom.Point;
@Entity
@Table(name = "paradas_ws")
public class ParadaWS implements Serializable {
private static final long serialVersionUID = 7772269835230124538L;
@Transient
private Logger logger = LogManager.getLogger(ParadaWS.class);
@Id
@NotNull
@Column(name = "codigo_parada")
private Integer codigoParada;
@NotNull
@Column(name = "descripcion_corta")
private String descripcionCorta;
@NotNull
@Column(name = "descripcion_larga")
private String descripcionLarga;
@NotNull
@Column(name = "codigo_municipio")
private Integer codigoMunicipio;
@NotNull
@Column(name = "utmx")
private Long utmX;
@NotNull
@Column(name = "utmy")
private Long utmY;
@NotNull
@Column(name="punto")
private Point punto;
@Id
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "operador")
private OperadorWS operador;
public ParadaWS(){
}
public ParadaWS(Integer codigoParada, String descripcionCorta, String descripcionLarga, Integer codigoMunicipio,
Long utmX, Long utmY, Point punto, OperadorWS operador) {
this.codigoParada = codigoParada;
this.descripcionCorta = descripcionCorta;
this.descripcionLarga = descripcionLarga;
this.codigoMunicipio = codigoMunicipio;
this.utmX = utmX;
this.utmY = utmY;
this.punto = punto;
this.operador = operador;
}
public Integer getCodigoParada() {
return codigoParada;
}
public void setCodigoParada(Integer codigoParada) {
this.codigoParada = codigoParada;
}
public String getDescripcionCorta() {
return descripcionCorta;
}
public void setDescripcionCorta(String descripcionCorta) {
this.descripcionCorta = descripcionCorta;
}
public String getDescripcionLarga() {
return descripcionLarga;
}
public void setDescripcionLarga(String descripcionLarga) {
this.descripcionLarga = descripcionLarga;
}
public Integer getCodigoMunicipio() {
return codigoMunicipio;
}
public void setCodigoMunicipio(Integer codigoMunicipio) {
this.codigoMunicipio = codigoMunicipio;
}
public Long getUtmX() {
return utmX;
}
public void setUtmX(Long utmX) {
this.utmX = utmX;
}
public Long getUtmY() {
return utmY;
}
public void setUtmY(Long utmY) {
this.utmY = utmY;
}
public Point getPunto() {
return punto;
}
public void setPunto(Point punto) {
this.punto = punto;
}
public OperadorWS getOperador() {
return operador;
}
public void setOperador(OperadorWS operador) {
this.operador = operador;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((codigoMunicipio == null) ? 0 : codigoMunicipio.hashCode());
result = prime * result + ((codigoParada == null) ? 0 : codigoParada.hashCode());
result = prime * result + ((descripcionCorta == null) ? 0 : descripcionCorta.hashCode());
result = prime * result + ((descripcionLarga == null) ? 0 : descripcionLarga.hashCode());
result = prime * result + ((operador == null) ? 0 : operador.hashCode());
result = prime * result + ((punto == null) ? 0 : punto.hashCode());
result = prime * result + ((utmX == null) ? 0 : utmX.hashCode());
result = prime * result + ((utmY == null) ? 0 : utmY.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ParadaWS)) {
return false;
}
ParadaWS other = (ParadaWS) obj;
if (codigoMunicipio == null) {
if (other.codigoMunicipio != null) {
return false;
}
} else if (!codigoMunicipio.equals(other.codigoMunicipio)) {
return false;
}
if (codigoParada == null) {
if (other.codigoParada != null) {
return false;
}
} else if (!codigoParada.equals(other.codigoParada)) {
return false;
}
if (descripcionCorta == null) {
if (other.descripcionCorta != null) {
return false;
}
} else if (!descripcionCorta.equals(other.descripcionCorta)) {
return false;
}
if (descripcionLarga == null) {
if (other.descripcionLarga != null) {
return false;
}
} else if (!descripcionLarga.equals(other.descripcionLarga)) {
return false;
}
if (operador == null) {
if (other.operador != null) {
return false;
}
} else if (!operador.equals(other.operador)) {
return false;
}
if (punto == null) {
if (other.punto != null) {
return false;
}
} else if (!punto.equals(other.punto)) {
return false;
}
if (utmX == null) {
if (other.utmX != null) {
return false;
}
} else if (!utmX.equals(other.utmX)) {
return false;
}
if (utmY == null) {
if (other.utmY != null) {
return false;
}
} else if (!utmY.equals(other.utmY)) {
return false;
}
return true;
}
@Override
public String toString() {
return "ParadaWS [codigoParada=" + codigoParada + ", descripcionCorta=" + descripcionCorta
+ ", descripcionLarga=" + descripcionLarga + ", codigoMunicipio=" + codigoMunicipio + ", utmX=" + utmX
+ ", utmY=" + utmY + ", punto=" + punto + ", operador=" + operador + "]";
}
}
OperadorWS 类:
package model.paradasws;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Store;
@Entity
@Table(name = "operadores_ws")
public class OperadorWS implements Serializable {
private static final long serialVersionUID = 1L;
@Transient
private Logger logger = LogManager.getLogger(OperadorWS.class);
/*
Atributos
*/
@Id
@NotNull
@Column(name = "codigo_operador")
private Integer codigoOperador;
@NotNull
@Column(name = "descripcion_corta")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
private String descripcionCorta;
@NotNull
@Column(name = "descripcion_larga")
private String descripcionLarga;
@NotNull
@Column(name = "direccion_web")
private String direccionWeb;
@NotNull
@Column(name = "telefono")
private String telefono;
/*
Métodos
*/
public OperadorWS(){
}
public OperadorWS(Logger logger, Integer codigoOperador, String descripcionCorta, String descripcionLarga,
String direccionWeb, String telefono) {
this.logger = logger;
this.codigoOperador = codigoOperador;
this.descripcionCorta = descripcionCorta;
this.descripcionLarga = descripcionLarga;
this.direccionWeb = direccionWeb;
this.telefono = telefono;
}
public Logger getLogger() {
return logger;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
public Integer getCodigoOperador() {
return codigoOperador;
}
public void setCodigoOperador(Integer codigoOperador) {
this.codigoOperador = codigoOperador;
}
public String getDescripcionCorta() {
return descripcionCorta;
}
public void setDescripcionCorta(String descripcionCorta) {
this.descripcionCorta = descripcionCorta;
}
public String getDescripcionLarga() {
return descripcionLarga;
}
public void setDescripcionLarga(String descripcionLarga) {
this.descripcionLarga = descripcionLarga;
}
public String getDireccionWeb() {
return direccionWeb;
}
public void setDireccionWeb(String direccionWeb) {
this.direccionWeb = direccionWeb;
}
public String getTelefono() {
return telefono;
}
public void setTelefono(String telefono) {
this.telefono = telefono;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((codigoOperador == null) ? 0 : codigoOperador.hashCode());
result = prime * result + ((descripcionCorta == null) ? 0 : descripcionCorta.hashCode());
result = prime * result + ((descripcionLarga == null) ? 0 : descripcionLarga.hashCode());
result = prime * result + ((direccionWeb == null) ? 0 : direccionWeb.hashCode());
result = prime * result + ((telefono == null) ? 0 : telefono.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof OperadorWS)) {
return false;
}
OperadorWS other = (OperadorWS) obj;
if (codigoOperador == null) {
if (other.codigoOperador != null) {
return false;
}
} else if (!codigoOperador.equals(other.codigoOperador)) {
return false;
}
if (descripcionCorta == null) {
if (other.descripcionCorta != null) {
return false;
}
} else if (!descripcionCorta.equals(other.descripcionCorta)) {
return false;
}
if (descripcionLarga == null) {
if (other.descripcionLarga != null) {
return false;
}
} else if (!descripcionLarga.equals(other.descripcionLarga)) {
return false;
}
if (direccionWeb == null) {
if (other.direccionWeb != null) {
return false;
}
} else if (!direccionWeb.equals(other.direccionWeb)) {
return false;
}
if (telefono == null) {
if (other.telefono != null) {
return false;
}
} else if (!telefono.equals(other.telefono)) {
return false;
}
return true;
}
@Override
public String toString() {
return "OperadorWS [codigoOperador=" + codigoOperador
+ ", descripcionCorta=" + descripcionCorta
+ ", descripcionLarga=" + descripcionLarga
+ ", direccionWeb=" + direccionWeb
+ ", telefono=" + telefono
+ "]";
}
}
我必须将这两行添加到我的配置中(我以编程方式执行):
cfg.setProperty("hibernate.search.default.directory_provider", "filesystem");
cfg.setProperty("hibernate.search.default.indexBase", "C:/Users/IN006/Desktop/paradas/indexLucene");
所以就是这样,我想添加Hibernate Search支持,使用他们的descripcionCorta和descripcionLarga属性来查找ParadaWS对象。
我该如何配置?我一直在查看官方文档,我需要在ParadaWS类中添加@Indexed注释。然后,需要将@Field注释添加到要将其切换为可搜索的每个属性。这是对的吗?
所以这些将是我对添加Hibernate Search支持的修改:
@Entity
@Table(name = "paradas_ws")
@Indexed
public class ParadaWS implements Serializable {
...
@NotNull
@Column(name = "descripcion_corta")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
private String descripcionCorta;
@NotNull
@Column(name = "descripcion_larga")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
private String descripcionLarga;
...
}
这够了吗?我可以使用这种方法进行搜索吗?
public void buscarSimilitudesNombreParada(String pNombreCorto){
openCurrentSession();
SearchFactory fact = getHibernateSearch();
FullTextSession txtSession = getFullTextSession();
QueryBuilder b = fact.buildQueryBuilder().forEntity(ParadaWS.class).get();
Query query = b.keyword()
.fuzzy()
.withEditDistanceUpTo(1)
.withPrefixLength(1)
.onField("descripcionCorta")
.matching(pNombreCorto)
.createQuery();
FullTextQuery txtQuery = txtSession.createFullTextQuery(query, ParadaWS.class);
List resultados = txtQuery.list();
for (Object obj : resultados) {
if(obj instanceof ParadaWS){
ParadaWS pws = (ParadaWS) obj;
LogHelper.logDebug(logger, "Una parada tras hibernate search: " + pws.toString(), true);
}
}
}
后来,当我习惯了Hibernate Search时,我想基于Point对象(Spatial features)实现搜索。
感谢您的帮助!
编辑:解决方案 最后,经过几次试验,我想出了解决方案...... ParadaWS课程仍然如下:
@Entity
@Table(name = "paradas_ws")
@Indexed
public class ParadaWS implements Serializable {
...
@Id
@NotNull
@Column(name = "codigo_parada")
@DocumentId
private Integer codigoParada;
@NotNull
@Column(name = "descripcion_corta")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
private String descripcionCorta;
@NotNull
@Column(name = "descripcion_larga")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
private String descripcionLarga;
...
@Id
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "operador")
@FieldBridge(impl = OperadorWSBridge.class)
private OperadorWS operador;
...
所以,我有必要建一座桥(我猜这是必须的,因为我有一个复合ID),所以这是我的OperadorWSBridge类:
package model.paradasws;
import org.hibernate.search.bridge.TwoWayStringBridge;
public class OperadorWSBridge implements TwoWayStringBridge {
@Override
public String objectToString(Object pObject) {
return ((OperadorWS) pObject).toString();
}
@Override
public OperadorWS stringToObject(String pStringValue) {
return OperadorWS.buildFromString(pStringValue);
}
}
这是OperadorWS的buildFromString方法(它的作用是解析使用toString()默认方法生成的String,所以我发布了两个):
public static OperadorWS buildFromString(String pOperadorStr){
String out = pOperadorStr;
out = out.replace("OperadorWS [codigoOperador=", "");
out = out.replace(", descripcionCorta=", ";");
out = out.replace(", descripcionLarga=", ";");
out = out.replace(", direccionWeb=", ";");
out = out.replace(", telefono=", ";");
out = out.replace("]", "");
String[] strOut = out.split(";");
OperadorWS act = new OperadorWS();
act.setCodigoOperador(Integer.parseInt(strOut[0]));
act.setDescripcionCorta(strOut[1]);
act.setDescripcionLarga(strOut[2]);
act.setDireccionWeb(strOut[3]);
act.setTelefono(strOut[4]);
return act;
}
@Override
public String toString() {
return "OperadorWS [codigoOperador=" + codigoOperador
+ ", descripcionCorta=" + descripcionCorta
+ ", descripcionLarga=" + descripcionLarga
+ ", direccionWeb=" + direccionWeb
+ ", telefono=" + telefono
+ "]";
}
但是,经过所有这些修改后,我仍然无法使用Hibernate Search 获取数据......你知道为什么吗?我的数据是通过另一个应用程序(每天运行)生成的,因此不是INDEXED 。这是一个很大的缺点,但必须索引所有数据:
public void indexarParadas(){
openCurrentSession();
getHibernateSearch();
FullTextSession txtSession = getFullTextSession();
txtSession.getTransaction().begin();
@SuppressWarnings("unchecked")
List<ParadaWS> paradas = txtSession.createQuery("from ParadaWS").list();
for (ParadaWS paradaWS : paradas) {
txtSession.index(paradaWS);
}
txtSession.getTransaction().commit();
}
毕竟,我已经能够让Hibernate Search工作了。