Búsqueda genérica en RAP: Anotaciones @Search para Fiori Elements

Kategorie
RAP
Veröffentlicht
Autor
Johannes

La búsqueda genérica permite a los usuarios buscar en múltiples campos simultáneamente con un único campo de búsqueda. En RAP, esta funcionalidad se controla completamente de forma declarativa a través de anotaciones @Search - sin una línea de JavaScript o código UI5.

El concepto de búsqueda genérica

En las apps Fiori Elements aparece un campo de búsqueda por defecto encima de la tabla. Sin configuración, solo busca en campos explícitamente definidos. Con anotaciones @Search determinas:

  • Qué campos se buscan
  • Qué tan similar deben ser las coincidencias (Fuzziness)
  • Qué tan importante es una coincidencia (Ranking)
┌─────────────────────────────────────────────────┐
│ 🔍 [ Munich ] 🔎 │ ← Campo de búsqueda genérico
├─────────────────────────────────────────────────┤
│ Booking-ID │ Cliente │ Origen │
├──────────────┼────────────────┼───────────────┤
│ 00001234 │ Hans Müller │ Munich │ ← Coincidencia
│ 00005678 │ Anna Schmidt │ Munich │ ← Coincidencia
│ 00009012 │ Munich AG │ Frankfurt │ ← Coincidencia (nombre cliente)
└─────────────────────────────────────────────────┘

Configuración básica: @Search.searchable

La anotación base activa la búsqueda a nivel de View:

@Search.searchable: true
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
key BookingId,
CustomerName,
DepartureCity,
ArrivalCity,
FlightDate
}

Importante: @Search.searchable: true a nivel de View es requisito para todas las demás anotaciones de búsqueda.

Definir campos buscables

Con @Search.defaultSearchElement: true marcas campos como buscables:

@Search.searchable: true
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
@Search.defaultSearchElement: true
key BookingId,
@Search.defaultSearchElement: true
CustomerName,
@Search.defaultSearchElement: true
DepartureCity,
@Search.defaultSearchElement: true
ArrivalCity,
-- Este campo NO se busca
FlightDate,
-- Campos técnicos no deberían ser buscables
@UI.hidden: true
CreatedBy
}

En este ejemplo, una búsqueda de “Munich” encuentra coincidencias en BookingId, CustomerName, DepartureCity y ArrivalCity - pero no en FlightDate o CreatedBy.

Fuzziness: Búsqueda por similitud

El fuzziness determina qué tan exactamente debe coincidir el término de búsqueda. El valor está entre 0.0 (cualquier coincidencia) y 1.0 (coincidencia exacta).

Valores de Fuzziness explicados

ValorSignificadoEjemplo: Búsqueda “Müller”
1.0ExactoSolo “Müller”
0.9Casi exacto”Müller”, “Mueller”
0.8Tolerante (Predeterminado)“Müller”, “Mueller”, “Muller”, “Müler”
0.7Muy toleranteTambién “Miller”, “Meller”

Fuzziness en código

@Search.searchable: true
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
-- Búsqueda exacta para IDs
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 1.0
key BookingId,
-- Búsqueda tolerante para nombres (errores tipográficos permitidos)
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
CustomerName,
-- Tolerancia media para ciudades
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
DepartureCity,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
ArrivalCity
}

¿Cuándo qué fuzziness?

Tipo de campoFuzziness recomendadoJustificación
IDs, Códigos1.0Coincidencia exacta requerida
Nombres0.7 - 0.8Considerar errores tipográficos, acentos
Ciudades, Países0.85 - 0.9Permitir variantes leves
Descripciones0.7 - 0.8Más flexible para texto libre
Direcciones email1.0Exacto

Ranking: Priorizar resultados de búsqueda

El ranking determina qué coincidencias se muestran primero:

@Search.searchable: true
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
-- Máxima prioridad: Número de reserva
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
key BookingId,
-- Prioridad media: Nombre de cliente
@Search.defaultSearchElement: true
@Search.ranking: #MEDIUM
CustomerName,
-- Baja prioridad: Ciudades
@Search.defaultSearchElement: true
@Search.ranking: #LOW
DepartureCity,
@Search.defaultSearchElement: true
@Search.ranking: #LOW
ArrivalCity
}

Niveles de Ranking

NivelUso
#HIGHIdentificadores primarios (IDs, números)
#MEDIUMCampos de negocio importantes (nombres, designaciones)
#LOWInformación secundaria (descripciones, comentarios)

Si el usuario busca “00001234”, las coincidencias en BookingId aparecen antes que las de CustomerName.

Ejemplo completo de reserva de vuelos

Aquí una CDS View completamente anotada para búsqueda de reservas de vuelos:

@EndUserText.label: 'Reserva de vuelo - Projection'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@Search.searchable: true
define view entity ZC_FlightBooking
as projection on ZI_FlightBooking
{
-- Clave primaria con ranking alto
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 1.0
@Search.ranking: #HIGH
@UI.lineItem: [{ position: 10 }]
key BookingId,
-- Datos de vuelo con ranking medio
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
@Search.ranking: #MEDIUM
@UI.lineItem: [{ position: 20 }]
CarrierId,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.9
@Search.ranking: #MEDIUM
@UI.lineItem: [{ position: 30 }]
ConnectionId,
-- Datos de cliente con alto fuzziness para errores tipográficos
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
@Search.ranking: #MEDIUM
@UI.lineItem: [{ position: 40 }]
CustomerName,
-- Ubicaciones buscables
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.85
@Search.ranking: #LOW
@UI.lineItem: [{ position: 50 }]
DepartureCity,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.85
@Search.ranking: #LOW
@UI.lineItem: [{ position: 60 }]
ArrivalCity,
-- Fecha NO buscable (usar filtros separados)
@UI.lineItem: [{ position: 70 }]
@UI.selectionField: [{ position: 10 }]
FlightDate,
-- Estado con Value Help, no buscable
@UI.lineItem: [{ position: 80 }]
@UI.selectionField: [{ position: 20 }]
BookingStatus,
-- Monto no buscable
@Semantics.amount.currencyCode: 'CurrencyCode'
@UI.lineItem: [{ position: 90 }]
FlightPrice,
@Semantics.currencyCode: true
CurrencyCode,
-- Campos administrativos ocultos y no buscables
@UI.hidden: true
CreatedBy,
@UI.hidden: true
CreatedAt,
@UI.hidden: true
LastChangedBy,
@UI.hidden: true
LastChangedAt
}

Mejores prácticas para campos buscables

Campos que deberían ser buscables

  • Claves primarias: BookingId, OrderId, CustomerNumber
  • Nombres: CustomerName, ProductName, Description
  • Códigos con significado: CarrierId, MaterialGroup
  • Ubicaciones: City, Country, Region

Campos que NO deberían ser buscables

  • Campos de fecha: Usar campos de filtro separados
  • Valores numéricos: Montos, cantidades vía filtros
  • Campos técnicos: GUIDs, Timestamps
  • Campos administrativos: CreatedBy, ChangedAt
  • Campos binarios: Flags, Status (mejor: Filtro con Value Help)

Ejemplo: Diseño bueno vs. malo

-- ❌ MALO: Todo buscable
@Search.searchable: true
define view entity ZC_Order {
@Search.defaultSearchElement: true
key OrderGuid, -- ¿GUID buscable?
@Search.defaultSearchElement: true
OrderDate, -- ¿Fecha buscable?
@Search.defaultSearchElement: true
TotalAmount, -- ¿Monto buscable?
@Search.defaultSearchElement: true
CreatedAt -- ¿Timestamp buscable?
}
-- ✅ BUENO: Selección dirigida
@Search.searchable: true
define view entity ZC_Order {
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
@Search.fuzzinessThreshold: 1.0
key OrderId, -- Número de pedido buscable
@Search.defaultSearchElement: true
@Search.ranking: #MEDIUM
@Search.fuzzinessThreshold: 0.8
CustomerName, -- Nombre de cliente buscable
@UI.selectionField: [{ position: 10 }]
OrderDate, -- Fecha como filtro
@Semantics.amount.currencyCode: 'Currency'
TotalAmount, -- Monto no buscable
@UI.hidden: true
CreatedAt -- Oculto
}

Consideraciones de rendimiento

Indexación

Los campos buscables deberían estar indexados en la base de datos:

-- En la definición de tabla
@AbapCatalog.tableCategory: #TRANSPARENT
define table zflight_book {
key client : abap.clnt not null;
key booking_id : abap.numc(10) not null;
-- Índice en campos frecuentemente buscados
customer_name : abap.char(80);
departure_city : abap.char(40);
arrival_city : abap.char(40);
}

Limitar cantidad de campos buscables

-- ❌ Demasiados campos buscables (problema de rendimiento)
-- 15+ campos con @Search.defaultSearchElement: true
-- ✅ Selección enfocada (5-8 campos)
@Search.defaultSearchElement: true
BookingId,
@Search.defaultSearchElement: true
CustomerName,
@Search.defaultSearchElement: true
DepartureCity,
@Search.defaultSearchElement: true
ArrivalCity,
@Search.defaultSearchElement: true
CarrierId

Grandes volúmenes de datos

Para grandes volúmenes de datos se recomienda:

@ObjectModel.resultSet.sizeCategory: #XS -- < 100 entradas
@ObjectModel.resultSet.sizeCategory: #S -- < 1.000 entradas
@ObjectModel.resultSet.sizeCategory: #M -- < 10.000 entradas
@ObjectModel.resultSet.sizeCategory: #L -- > 10.000 entradas

Para grandes volúmenes de datos, desactivar búsqueda automática al escribir y forzar búsqueda explícita.

AnotaciónValoresDescripción
@Search.searchabletrue/falseActiva búsqueda a nivel de View
@Search.defaultSearchElementtrue/falseCampo es buscable
@Search.fuzzinessThreshold0.0 - 1.0Umbral de similitud
@Search.ranking#HIGH, #MEDIUM, #LOWPrioridad en resultados

Combinación con filtros

La búsqueda genérica complementa, pero no reemplaza los filtros:

@Search.searchable: true
define view entity ZC_FlightBooking
{
-- Buscable Y como filtro
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
@UI.selectionField: [{ position: 5 }]
key BookingId,
-- Solo buscable (no necesita filtro explícito)
@Search.defaultSearchElement: true
CustomerName,
-- Solo como filtro (no buscable)
@UI.selectionField: [{ position: 10 }]
FlightDate,
-- Solo como filtro con Value Help
@UI.selectionField: [{ position: 20 }]
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_BookingStatusVH' }
}]
BookingStatus
}

Conclusión

La búsqueda genérica en RAP ofrece una forma poderosa y declarativa para funciones de búsqueda amigables:

AspectoRecomendación
Activación@Search.searchable: true en View
Campos5-8 campos de negocio relevantes
Fuzziness1.0 para IDs, 0.8 para nombres
Ranking#HIGH para claves primarias
RendimientoÍndices, cantidad limitada de campos

Con pocas anotaciones logras una función de búsqueda profesional que permite a los usuarios encontrar datos rápidamente.

Artículos relacionados