services/api/src/modules/interpretation/real-estate-lexicon.js

Descripción general

Este módulo define el léxico inmobiliario inicial en es-MX. Toma formas lingüísticas como sinónimos, abreviaturas y errores ortográficos registrados, y las vincula con valores ya existentes del dominio. El archivo no crea dominios nuevos; solo reconoce texto y marca explícitamente lo que queda fuera de contrato o fuera de alcance.

[!IMPORTANT] Este módulo solo reconoce términos. No decide intenciones ni extrae parámetros. Esa capa de reglas pertenece a NLU-02, según el propio encabezado del archivo.

Cómo funciona

flowchart TD
    Input[Texto original]
    Norm[text normalization]
    Forms[LEXICON_ENTRIES]
    Index[FORM_INDEX]
    Match[findLexiconMatches]
    Output[Matches ordenados]

    Forms --> Index
    Input --> Norm
    Norm --> Match
    Index --> Match
    Match --> Output

El flujo empieza con un texto original. Luego, el módulo normaliza el texto y cada forma del léxico. Después, construye un índice plano de formas normalizadas, ordenado de la más larga a la más corta. Por último, findLexiconMatches recorre ese índice, verifica límites de palabra, evita solapes y devuelve coincidencias con su fragmento original. fileciteturn0file18turn0file19

Componentes clave

listLexiconForms [badge:public]

{
    "title": "listLexiconForms",
    "content": "Devuelve una lista plana de formas del l\u00e9xico para auditor\u00eda y pruebas. Cada elemento incluye entryId, text, variant y normalized.",
    "type": "function",
    "filePath": "services/api/src/modules/interpretation/real-estate-lexicon.js",
    "badges": [
        "public"
    ]
}

Esta función expone la superficie declarativa del léxico en formato plano. Sirve para inspección y verificación, sin modificar la estructura interna. El propio archivo la describe como una lista para auditoría y pruebas.

findLexiconMatches [badge:public]

{
    "title": "findLexiconMatches",
    "content": "Reconoce t\u00e9rminos del l\u00e9xico dentro de un texto y devuelve coincidencias ordenadas por posici\u00f3n. Emite facetas o lecturas ambiguas, seg\u00fan la entrada.",
    "type": "function",
    "filePath": "services/api/src/modules/interpretation/real-estate-lexicon.js",
    "badges": [
        "public"
    ]
}

Esta función es el núcleo operativo del módulo. Usa coincidencia exacta sobre la forma normalizada, con límites de palabra y sin coincidencia difusa. También conserva la procedencia exacta del fragmento original mediante toOriginalSpan. fileciteturn0file18turn0file19

LEXICON_ENTRIES

Es el catálogo principal de entradas. El módulo lo congela con Object.freeze, y también congela cada entrada individual. Las entradas combinan id, forms y facets, o bien id, forms y readings cuando el término es ambiguo.

FORM_VARIANTS

Contiene las variantes declaradas para cada forma textual. El módulo acepta exactamente estas tres: synonym, abbreviation y misspelling. Las funciones internas convierten cualquier forma en string al variant synonym.

LEXICON_VERSION

Esta constante fija la versión declarativa del léxico en "1". Las pruebas de versionado la tratan como una superficie independiente del contrato y del registro de capacidades. fileciteturn0file0turn0file17

Datos y campos

[
    {
        "name": "LEXICON_VERSION",
        "type": "string",
        "required": true,
        "description": "Versión declarativa del léxico. El archivo exporta \"1\"."
    },
    {
        "name": "FORM_VARIANTS",
        "type": "string[]",
        "required": true,
        "description": "Variantes permitidas para una forma: synonym, abbreviation y misspelling."
    },
    {
        "name": "LEXICON_ENTRIES",
        "type": "Array<LexiconEntry>",
        "required": true,
        "description": "Catálogo congelado de entradas del léxico."
    },
    {
        "name": "LexiconEntry",
        "type": "object",
        "required": true,
        "description": "Entrada declarativa que agrupa formas y facetas, o formas y lecturas ambiguas.",
        "children": [
            {
                "name": "id",
                "type": "string",
                "required": true,
                "description": "Identificador estable de la entrada."
            },
            {
                "name": "forms",
                "type": "Array<string | FormRecord>",
                "required": true,
                "description": "Formas reconocidas por el índice."
            },
            {
                "name": "facets",
                "type": "Array<Facet>",
                "description": "Facetas aplicadas a todas las formas de la entrada."
            },
            {
                "name": "readings",
                "type": "Array<Array<Facet>>",
                "description": "Lecturas alternativas para términos ambiguos."
            }
        ]
    },
    {
        "name": "FormRecord",
        "type": "object",
        "required": true,
        "description": "Forma marcada como abreviatura o error ortográfico.",
        "children": [
            {
                "name": "text",
                "type": "string",
                "required": true,
                "description": "Texto literal de la forma."
            },
            {
                "name": "variant",
                "type": "string",
                "required": true,
                "description": "Una de synonym, abbreviation o misspelling."
            }
        ]
    },
    {
        "name": "Facet",
        "type": "object",
        "required": true,
        "description": "Etiqueta semántica asociada a una coincidencia.",
        "children": [
            {
                "name": "category",
                "type": "string",
                "required": true,
                "description": "Categoría semántica."
            },
            {
                "name": "value",
                "type": "string | number | object | boolean",
                "required": true,
                "description": "Valor asociado a la categoría."
            }
        ]
    }
]

forms

Cada entrada acepta una lista de formas. Una forma puede ser un string simple o un objeto { text, variant }. El archivo usa los helpers ab y typo para marcar abreviaturas y faltas ortográficas registradas.

facets

Cuando una entrada no es ambigua, sus facets aplican a todas las formas. Esas facetas apuntan a valores del dominio ya existentes. El archivo las organiza por categoría semántica, no por reglas de interpretación.

readings

Cuando una forma es ambigua, la entrada usa readings. En ese caso, exactamente una lectura debe aplicar, y la capa superior debe pedir aclaración. El módulo no elige entre lecturas alternativas.

  • propertyType
    • house
    • apartment
    • land
    • office
    • commercial
    • industrial
    • building
  • operationType
    • sale
    • rent
    • temporary_rent
    • presale
    • exchange
    • auction
    • transfer
  • feature
    • bedrooms
    • halfBathrooms
    • bathrooms
    • parkingSpots
  • areaUnit
    • { unit: "m2", factor: 1 }
    • { unit: "m2", factor: 10000 } para hectáreas
  • areaQualifier
    • constructionArea
    • landArea
  • amenity
    • pool
    • gym
    • event_room
    • elevator
    • security
    • green_areas
    • roof_garden
    • visitor_parking
    • pet_friendly_common_area
  • pet
    • hasPets
    • petFriendlyRequired
  • currency
    • MXN
    • USD
    • EUR
  • magnitude
    • multiplier: 1000
    • multiplier: 1000000
    • multiplier: 1000000, impliedCurrency: "MXN"
  • amountWord
    • 500000
  • numberWord
    • valores escritos desde 0 hasta 900
  • budgetBound
    • max
    • min
    • range
    • approx
  • periodicity
    • month
    • week
    • day
  • role
    • seek
    • offer
    • ambiguous
  • intentCue
    • valores como discover.search, publish.start_offer, discover.refine, discover.save, discover.allow_recommendations, discover.show_matches, discover.recover, discover.select_existing, listing.inspect, publish.continue, attend.leads, attend.activity, nav.wall, system.help
  • contextRef
    • { ref: "visibleResults", ordinal }
    • { ref: "activeSearch" }
  • negation
    • true
  • locationCue
    • true
  • unsupportedField
    • texto descriptivo de la limitación
  • outOfScope
    • texto descriptivo de la solicitud fuera de alcance
  • bodega
    • propertyType: warehouse
    • amenity: storage
  • cerca de
    • budgetBound: approx
    • locationCue: true
  • $
    • currency: MXN
    • currency: USD
  • mascota
    • pet: hasPets
    • pet: petFriendlyRequired
  • el cuarto
    • contextRef: visibleResults ordinal 4
    • feature: bedrooms
  • jardin
    • amenity: green_areas
    • unsupportedField: Jardin privado
  • unsupportedField
    • amueblado
    • planta baja
    • vista al mar
    • cuarto de servicio
    • a estrenar
    • cerca del metro
  • outOfScope
    • comparar
    • agendar una visita
    • cuanto vale
    • negociar
    • credito
    • contrato de arrendamiento

Comportamientos

  • ab(text) — Construye una forma con variant: "abbreviation".
  • typo(text) — Construye una forma con variant: "misspelling".
  • toFormRecord(form) — Normaliza una forma textual simple a { text, variant: "synonym" }.
  • listLexiconForms() — Devuelve una vista plana del índice para auditoría y pruebas.
  • findLexiconMatches(text) — Devuelve coincidencias ordenadas por posición, con facets o readings según corresponda. fileciteturn0file0turn0file18

Reglas internas de coincidencia

El módulo construye FORM_INDEX a partir de todas las entradas. Luego, ordena las formas normalizadas de la más larga a la más corta. Así, una forma más específica gana frente a una más corta. El propio comentario del archivo lo ejemplifica con estacionamiento de visitas frente a estacionamiento.

Procedencia textual

Cada coincidencia conserva el span sobre el texto original y el matched exacto. El módulo usa toOriginalSpan para regresar desde el texto normalizado al texto escrito por la persona. Esa trazabilidad es parte del contrato del sistema. fileciteturn0file18turn0file19

Flujo

1. Cargar entradas | `LEXICON_ENTRIES` agrupa todos los términos reconocidos.
2. Expandir formas | Cada forma se convierte en un registro normalizado en `FORM_INDEX`.
3. Normalizar texto | `normalizeForMatching` prepara el texto para búsqueda.
4. Buscar coincidencias | `findLexiconMatches` recorre las formas de mayor a menor longitud.
5. Verificar límites | `hasBoundaries` evita coincidencias dentro de otras palabras.
6. Reservar fragmentos | El índice `occupied` impide solapes entre coincidencias.
7. Restaurar span original | `toOriginalSpan` devuelve el fragmento exacto del texto de entrada.
8. Emitir resultado | El módulo devuelve coincidencias ordenadas por posición.

Casos límite y comportamiento sensible

[!WARNING] findLexiconMatches no hace coincidencia difusa. Solo reconoce errores ortográficos que ya están registrados en el catálogo.

[!WARNING] Las coincidencias no se solapan. Si una forma larga ocupa un tramo, las formas más cortas de ese tramo se descartan. El índice occupied impone esa regla.

[!IMPORTANT] Una entrada con readings no produce facets. Produce una coincidencia ambigua, y la capa superior debe resolverla.

[!NOTE] El módulo evita términos demasiado generales para la ubicación. Por ejemplo, en y por no forman parte del léxico. La extracción de ubicación se reserva para una etapa estructural posterior.

[!CAUTION] Las solicitudes marcadas como unsupportedField o outOfScope no se fuerzan a un campo existente. El archivo las conserva como limitaciones explícitas.

Relacionado

Este archivo se integra con services/api/src/modules/interpretation/text-normalization.js, que normaliza acentos, mayúsculas, espacios y símbolos como ², y mantiene el mapa de posiciones al texto original. También se relaciona con services/api/src/modules/interpretation/deterministic-interpreter.js, que importa LEXICON_VERSION y findLexiconMatches para construir la interpretación determinista. fileciteturn0file19turn0file14

Las pruebas del módulo confirman que el léxico carga sin variables de entorno, que detecta formas como Busco depto en renta, y que su versión participa en la política de versionado independiente de contrato y registro de capacidades. fileciteturn0file7turn0file8turn0file17