11 puntos por newcodes7 2026-01-19 | 27 comentarios | Compartir por WhatsApp

Introducción del proyecto

  • NewCodes es un servicio de curación de blogs técnicos de empresas
  • Arquitectura Spring Boot + PostgreSQL
  • Implementación de la función de autocompletado de búsqueda: recomendaciones basadas en Term, búsqueda con descomposición de jamo, búsqueda por consonantes iniciales y recomendación de páginas de empresas

Detección del problema de rendimiento

  • La tabla Term acumuló 110 mil registros
  • El tiempo de respuesta de la API aumentó a más de 1000 ms
  • Objetivo: responder en menos de 100 ms

Primer intento: agregar índices (1000 ms → 700 ms)

  • Creación de índices para optimizar búsquedas de prefijo con LIKE usando varchar_pattern_ops
  • Creación de índices con la opción CONCURRENTLY sin interrumpir el servicio
  • Aplicación de índices por separado a las columnas term, decomposed_term y chosung

Segundo intento: índice con la función LOWER (700 ms → 110 ms)

  • Se detectó un problema de full scan causado por el uso de la función LOWER()
  • Creación de un índice basado en funciones (Functional Index)
  • Reconfiguración del índice con la forma LOWER(nombre_de_columna) varchar_pattern_ops

Tercer intento: JOIN → EXISTS (110 ms → 100 ms)

  • El INNER JOIN entre Corporation y Article era un cuello de botella de rendimiento
  • Se cambió a una subconsulta con EXISTS para reducir el rango de escaneo
  • Optimización para verificar solo la “existencia de datos”

Cuarto intento: desnormalización e índice covering (100 ms → 90 ms)

  • Se agregó la columna total_frequency para eliminar operaciones de agregación
  • Las operaciones GROUP BY y SUM se reemplazaron por valores precalculados
  • Reducción de operaciones de I/O con un índice covering
  • Inclusión de term y total_frequency en el índice con la cláusula INCLUDE

Quinto intento: JDBC Template (90 ms → 80 ms)

  • Eliminación del overhead de JPA/Hibernate
  • Ejecución directa de consultas con JDBC Template
  • En consultas simples, omitir la capa ORM resultó efectivo

Resolución del problema de Rate Limiting en Nginx

  • Configuración inicial: límite de 2 veces por segundo, burst 10
  • Se producían fallos de solicitud por el debouncing de 100 ms
  • Mejora: se cambió a 10 solicitudes por segundo, burst 20
  • Cambio del status code de 444 → 429

Reducción del tamaño de los datos de respuesta

  • Se eliminaron los nombres de campos JSON y se cambió a una respuesta basada en arreglos
  • Los tipos se diferenciaron con números (0: Corporation, 1: Theme, 2: Term)
  • Reducción del tiempo de transmisión por red

Procesamiento en paralelo con CompletableFuture

  • Las consultas de Corporation, Theme y Term se ejecutaron de forma independiente y simultánea
  • En comparación con la ejecución secuencial, solo tomó el tiempo de la respuesta más lenta
  • Se agregaron ExecutorService y manejo de excepciones

Resultado final

  • De 1000 ms al inicio → 80 ms al final (servidor de desarrollo), 40 ms (servidor de producción)
  • Mejora de rendimiento de más del 90 %

Aprendizajes clave

  • La importancia de definir bien el problema y la dirección a seguir
  • El equilibrio entre el uso de IA y la revisión por parte del desarrollador
  • La necesidad de diseñar desde la perspectiva de toda la arquitectura
  • Selección del tipo de índice: simple/compuesto/covering
  • Cuidado con la invalidación de índices al usar funciones
  • Comprensión del funcionamiento interno de JPA
  • Análisis del plan de ejecución de consultas con EXPLAIN

Próximas mejoras

  • Uso de la estructura de datos Trie
  • Caché de términos buscados con frecuencia
  • Uso de CDN (en caso de un servicio global)

27 comentarios

 
moderator 2026-01-21

Soy el administrador.
Actualmente vemos que la discusión en los comentarios se está sobrecalentando, ya que se está mezclando de forma compleja con aspectos no relacionados con el contenido técnico de la publicación, así que les compartimos este aviso.

Las discusiones técnicas y el feedback siempre son bienvenidos.
Puede haber opiniones diversas, pero al escribir comentarios les pedimos mantener la cortesía básica hacia los demás y centrar la discusión en la lógica; también les pedimos que se enfoque en el contenido de la publicación en sí, más que en personas o trayectorias.

Por favor, vuelvan a revisar la guía para escribir comentarios en Cómo usar el sitio.

  • Por favor, hablen con amabilidad y respeto.
  • Por favor, no ataquen directamente al autor.

Como referencia, sobre las publicaciones marcadas ya se están tomando medidas a nivel de registros y del sistema, y seguiremos mejorando continuamente las políticas operativas relacionadas y el sistema.
Además, si tienen opiniones o feedback sobre la moderación, no duden en escribirnos por correo.

 
kunggom 2026-01-21

Sí, entendido.

 
kunggom 2026-01-20

Creo que el tono de los comentarios está un poco raro. ¿Quizás cambiaron el título o el contenido en comparación con cuando se publicó por primera vez? No me parece extraño en sí que se publique un artículo de este nivel.
También hay opiniones como: "No escribirían algo así en el blog técnico de una empresa", pero definir el rendimiento objetivo y repetir mejoras para alcanzarlo es algo que suele aparecer en blogs técnicos corporativos.
Por ejemplo, de lo que vi hace tiempo, hay un artículo como el siguiente.

 
kuthia 2026-01-21

Estoy de acuerdo con lo que dices.
Pero creo que la situación actual es una crítica a la actitud del usuario que abusó del sistema. Decir si la calidad de la publicación es buena o mala me parece que se sale del punto en discusión.
Las reacciones poco favorables probablemente se deben al antecedente de abuso del autor. Creo que hablar de cómo es el contenido es un comentario innecesario.

 
kunggom 2026-01-21

Por eso justamente esa parte es la que me genera dudas.
Más bien, si todos hubieran reaccionado diciendo algo como "¡Esta persona está abusando del sistema!", probablemente no habría dejado un comentario así. Pero como la mayoría de los comentarios hablaban del nivel del texto original, eso es lo que me parece raro. Si de verdad el problema fuera el abuso, entonces mencionar el nivel del texto no sería un añadido completamente innecesario, ¿no?

 
nemorize 2026-01-20

Estoy de acuerdo.
Incluso viendo eso de "¡Empecé a hacerlo yo solo en el ejército desde mayo de 2025!", ni siquiera parece un blog corporativo...

Claro, es difícil negar que lo compartido es "un trabajo que obviamente había que hacer",
y también es cierto que "no habla de ningún diferenciador y el contenido está al nivel de una práctica personal", pero

¿GeekNews era un espacio con un ambiente donde no se podía compartir este tipo de cosas?
¿No se pueden compartir experiencias de haber hecho trabajos que obviamente había que hacer?
¿No se pueden compartir experiencias que no tienen un diferenciador?
¿No se pueden compartir experiencias que están al nivel de una práctica personal?

 
ifmkl 2026-01-20

Puede que se haya visto así. Hubo dos razones por las que dejé el comentario de abajo. Primero, la publicación que subió antes a Show GN fue marcada por abuso. Un día después, resumió su propia entrada de velog y volvió a publicar un texto nuevo, pero ¿el contenido en sí realmente era algo que mereciera subirse? Si me preguntan si se notaban las inquietudes y el esfuerzo del propio autor, como dijeron otras personas, la búsqueda es un área en la que la tecnología ya está bastante desarrollada de forma general, y más que por la parte técnica, dejé ese comentario porque el contenido del blog me pareció, de manera indirecta, una extensión de la promoción de su propio servicio.

 
kunggom 2026-01-20

Parece que lo más importante es que quedó mal visto por la marca de abuso.
Como el contenido del blog en sí mismo también es, al igual que en los blogs técnicos de otras empresas, una extensión de la promoción de su propio servicio, me parece que excluirlo simplemente por eso es un criterio bastante sensible.
Y en cuanto a si en este texto se veían las dudas y el esfuerzo del propio autor, cuando se descartó la hipótesis de que poner un índice mejoraría el rendimiento, revisó también el plan de ejecución y, considerando la lógica de negocio, fue mejorando de forma iterativa cambiando la consulta o el esquema hasta alcanzar el rendimiento objetivo; me parece que eso sí cuenta como reflexión y esfuerzo suficientes.

 
ifmkl 2026-01-19

También fui al blog y leí el texto original. Siento que hay cierta brecha entre el título y el contenido real. La funcionalidad que implementaste y la dirección de las mejoras ya son aspectos que están implementados e incorporados en varios proyectos de código abierto existentes, y lo que trabajaste fue más bien sofisticar la búsqueda que inicialmente habías implementado de forma simple por primera vez en tu propio servicio; pero viendo solo el título da la impresión de que hubieras hecho una gran mejora algorítmica. Tu publicación anterior también fue marcada como promoción, así que creo que quizá haría falta pensarlo un poco más al momento de redactar.

 
newcodes7 2026-01-19

Si les dio esa impresión, lo siento. Creo que cada persona espera cosas distintas al ver el título. Aun así, es cierto que debo procurar escribir títulos lo más claros posible para que lo que se espere del contenido sea similar. Lo tendré presente.

Además, me gustaría que lo vieran por separado del artículo anterior. En el artículo anterior intenté hacer upvote usando dos cuentas que no estaba utilizando y por eso fue marcado. Ese fue claramente un error mío, y quisiera aclarar que no fue un problema del artículo en sí.

 
click 2026-01-19

Me da curiosidad si consideraron usar un índice GIN en lugar de un índice con lower(). Total, como ya usaron SQL raw con JdbcTemplate, ya que están en eso, ¿qué tal FTS?

El enfoque asíncrono con CompletableFuture.supplyAsync() también usa el commonPool de ForkJoinPool si no se especifica un ExecutorService aparte, así que
si aumenta mucho la cantidad de conexiones concurrentes hasta el punto de saturar el commonPool que se usa en lugar del hilo de request (núcleos de CPU - 1), puede que no lo soporte bien.
Esa parte probablemente se podría resolver de forma más limpia cambiando a un enfoque reactivo o subiendo la versión de la JVM para introducir hilos virtuales.

 
newcodes7 2026-01-19

¡Hola! Antes que nada, muchísimas gracias por dejar un comentario con feedback.

Consideré que el índice GIN no era necesario en este caso. En la API actual de recomendaciones de autocompletado de búsquedas, solo necesitamos el term en sí. No es necesario saber a qué articles pertenece ese term.
En cambio, en la API de búsqueda sí estamos usando un índice similar al GIN. Aprovechamos paradeDB, una extensión de Postgres, para usar un índice BM25.
En la publicación no aparece en detalle, pero actualmente estamos usando un ExecutorService definido por separado. De todos modos, como mencionaste, más adelante también vamos a considerar un enfoque reactivo o hilos virtuales.

 
newcodes7 2026-01-20

Quisiera pedir disculpas por esta publicación y la anterior.
Haber hecho upvote con 2 cuentas que no uso fue un error mío y una acción tonta.

Como era un proyecto en el que había puesto mucho tiempo y esfuerzo, quise que llamara más la atención de la gente y actué mal.
Pero, aunque hubiera una razón así, eso no justifica haber incumplido las reglas.
Por los upvotes que di a la ligera, seguramente la publicación de alguien tuvo que bajar de posición, y también habré alterado el orden del sitio.

Además, creo que publicar otro texto nuevo al día siguiente de haber sido flagged pudo prestarse bastante a malentendidos.
Si soy sincero, como no había una restricción específica de uso del sitio, pensé si estaría bien volver a publicar de inmediato. Fue una falta de criterio de mi parte.
Ahora que lo pienso, independientemente de si había sanción o no, debí haberme contenido.
Si lo pienso desde la postura contraria, a mí tampoco me habría parecido bien que alguien hiciera lo mismo en un espacio que me gusta.

Desde que empecé a desarrollar, siempre había pensado y practicado la idea de que "compartir" es algo bueno sin condiciones.
Pero esta vez entendí que hay espacios adecuados para compartir y también momentos adecuados para hacerlo.
Además, sentí que si yo entraba por primera vez a un espacio al que otras personas le tienen cariño e interés, lo correcto era primero respetarlas al máximo.
Por eso debí haber leído primero las reglas de uso y observar también el ambiente del sitio para no actuar de una manera que fuera en contra de eso.

Reconozco mi error y presento esta explicación aunque sea de esta manera.
La próxima vez procuraré participar de una forma más madura.

 
roxie 2026-01-24

:+1:

 
winterjung 2026-01-20

Lo leí con mucho interés. Al principio pensé: ¿será simplemente un artículo sobre haber puesto un índice?, pero me gustó que no se quedara solo en eso, sino que probaran varios métodos y los compartieran. Más adelante, como mencionaste, estaría bueno probar con un trie, o incluso mejorar el sistema dándoles más peso a los términos que han sido tendencia en búsquedas recientes.

Una cosa que me da curiosidad es que consultan tanto term como decomposed term con una condición OR, pero como decomposed term parecería ser un superconjunto, me pregunto si no bastaría con consultar solo ese campo. Porque aunque la consulta sea “neng”, al descomponerse como “n-e-o-ng”, imagino que igual se encontraría “Naver”. Y también debería encontrar de la misma manera los casos en que el term real sea “neng”.

 
newcodes7 2026-01-21

Como mencionaste, es suficiente con consultar solo con el término descompuesto. Ahora que esto existe, term era una condición innecesaria, pero creo que no lo había tenido en cuenta. Gracias a eso, ya lo corregí. ¡Gracias!

 
skageektp 2026-01-20

Me da la impresión de que esto no es precisamente el tipo de contenido que la gente viene a ver en GeekNews, ¿no?

 
kunggom 2026-01-20

Realmente no entiendo qué tiene de tan grandioso.
No estamos hablando de 1 millón o 10 millones de registros; desde el título ya queda claro que es una escala de apenas un poco más de 100 mil, así que ¿no es raro esperar algún tipo de optimización espectacular en lugar de centrarse en lo básico? Me pregunto qué era exactamente lo tan grandioso que esperaban.
No tengo claro por qué una publicación que muestra cómo ir ajustando las cosas una por una, centrándose en lo fundamental cuando la DB no está bien optimizada, debería ser tratada como si fuera puro bait. En mi opinión, ese ambiente excluyente de "si no es lo mejor de lo mejor, está mal siquiera publicarlo aquí" es perjudicial.

 
crawler 2026-01-20

> ¿No es un poco extraño esperar algún tipo de optimización grandilocuente en lugar de centrarse en lo básico?

Las personas ven hasta donde les alcanza su conocimiento.
Para facilitar la comprensión, ahora mismo estoy pensando en el ejemplo de crear un tablero de publicaciones.

A los desarrolladores principiantes se les recomendaba mucho como primer portafolio hacer un tablero de publicaciones.

Si se piensa de forma simple, es sencillo.
Subes una publicación, aparece en la lista y listo. Si se hace de verdad de la forma más simple, quizá ni siquiera haga falta una base de datos en el backend.

Pero las personas ven hasta donde les alcanza su conocimiento.
Si se hace un tablero de publicaciones en serio, empezando por la base de datos, función de comentarios, inicio de sesión, y si evolucionas el inicio de sesión, autenticación con OAuth o JWT; incluso en la simple función de escribir publicaciones, adjuntar imágenes y videos, soporte de formato de texto, y seguridad empezando por XSS.

Incluso con el mismo texto, la imagen que cada lector se forma puede variar mucho según sus conocimientos previos.

Entiendo qué tipo de autocompletado imaginó kunggom al ver el título.

Pero cada lector ha vivido una vida distinta y, al final, las funciones que imaginaron los lectores seguramente serán muy diferentes entre sí.

También entiendo con qué intención está escribiendo el comentario.
Yo también estoy de acuerdo con esa opinión, pero confío en que sabe que no encaja mucho con la situación de quien escribió este artículo ahora.

 
kunggom 2026-01-20

¿Podrían explicar un poco más la parte de que es "un comentario que no encaja mucho con la situación de la persona que escribió el post"?
Según el texto original, se indica explícitamente que ese proyecto es "un proyecto personal y no un servicio con muchísimo tráfico ni que tenga que generar ingresos". Por lo tanto, si hubiera algún tipo de optimización rimbombante, se puede suponer que sería solo por curiosidad personal o algo por el estilo, y no por una razón práctica. Así que no me parece extraño que no se haya invertido ese nivel de esfuerzo técnico, y por eso no entiendo por qué las reacciones de algunas personas son especialmente negativas. Además, tampoco es que las cifras citadas en el título contradigan el contenido del texto.

 
crawler 2026-01-21

No creo que kunggom sea un desarrollador con tan poco conocimiento de base como para no entender siquiera la analogía del tablero que mencioné.

Creo que la diferencia de opinión ahora viene, ante todo, de cómo percibimos a los usuarios que hacen abuso, así que lo diré por última vez.

Lo que yo esperaba era una búsqueda semántica.
La búsqueda semántica no es en absoluto un tema irrealizable en esta época de furor por la IA, y confío en que sabe que incluso una persona por su cuenta puede implementarla perfectamente.

Desde el principio, cuando hacemos clic en un título no es que lo hagamos entendiendo el contexto de quien escribió el post, pero lo que quiero decir es que, aunque no sea un servicio con muchísimo tráfico o que tenga que generar ingresos, igual es algo totalmente implementable.

Y yo ahora mismo estoy hablando solo del título.
> Según el post original, ese proyecto ~

Estoy hablando de la imagen que imaginé al ver el título, así que esa parte no hace falta en esta conversación.

> La situación de la persona que escribió el post ahora mismo
Creo que ya entiendo qué piensa kunggom sobre la persona que escribió el post. Parece que la ve como un desarrollador principiante al que hay que comprender sin importar lo que escriba.

Como dije ayer, si no lo hubieran marcado, yo también habría estado de acuerdo con eso, pero desde el momento en que manipuló las recomendaciones de su post, esta conversación deja de tener sentido.

> Y si realmente piensa que es un problema que una persona a la que se le detectó abuso vuelva a escribir al día siguiente

Usted dijo eso arriba.
Si alguien tiene la libertad de seguir escribiendo incluso después de haber sido marcado, también existe la libertad de criticar eso.
Como usted mismo dijo, si le parece problemático hablar con un poco más de dureza en los comentarios hacia alguien que fue marcado, en vez de señalarlo en los comentarios, le sugiero que se lo plantee al equipo de moderación.

 
kunggom 2026-01-21

Supongo que te referías a compartir una experiencia de optimización para un tipo de servicio que recomienda candidatos de búsqueda de forma muy acertada incluso si el usuario escribe algo desastroso, por ejemplo usando embeddings.
Si era algo así, me parece que más bien sería algo que uno esperaría de un título como "recomendación de términos de búsqueda", pero entiendo qué era lo que esperabas.

Entiendo una postura crítica frente al abuso, pero la última oración me decepciona un poco porque parece que cambia sutilmente el eje del argumento, de la falta de madurez técnica a una cuestión de incumplimiento de las reglas de la comunidad, y suena como un torpe intento de decir "voy a refutarte con tu propia lógica y tus propios argumentos".
Si hubieras criticado desde el principio solo el abuso, habría sido más convincente. Si de verdad hubiera sido así, aunque ese texto realmente hubiera contenido lo que dices que originalmente esperabas, como optimización de embeddings vectoriales en DBMS modernos, o aunque se hubiera usado un "título humilde", de todos modos habría habido una reacción hostil por el historial reciente de abuso del autor, y sobre ese punto yo no tendría ninguna objeción. Porque eso no tiene mucho que ver con el contenido técnico.

Lo que yo cuestiono es por qué ese patrón se expresa como una crítica a la "falta de madurez técnica". Si el abuso es una conducta inaceptable, entonces naturalmente merece ser criticado sin importar el contenido. Entonces, ¿qué razón habría para meter críticas al contenido? Sin embargo, los comentarios que se dejaron aquí, casi sin excepción, tienen el matiz de que el contenido es técnicamente inmaduro. Incluso tú, crawler, usaste una comparación como "hacer un tablero como desarrollador principiante" y me dijiste que "uno ve hasta donde sabe". Si es así, ¿no tendríamos que sospechar que el abuso en realidad es un problema secundario, algo que se añadió después?

Según lo que dicen los comentarios, aunque el texto original realmente hubiera sido del tipo de contenido que crawler esperaba, igual lo habrían criticado solo por el abuso en sí. O acaso, aunque haya habido abuso, si el contenido del texto les parece de su agrado, ¿ya no hace falta ejercer la libertad de hablar "con dureza"?
Por eso vuelvo a preguntarlo. Si de verdad están criticando al autor original por su abuso, ¿hay alguna razón por la que hayan escrito comentarios centrados más en críticas al contenido que en el abuso mismo?

 
kunggom 2026-01-21

¿Podrías indicar cuál es la base para la parte de que "interfirió con la libertad de expresión de otras personas"? Eso no lo entiendo muy bien. No es como si yo tuviera permisos de moderación sobre este espacio y pudiera impedir que otras personas escriban publicaciones o comentarios. De hecho, acabas de escribir sin problema un comentario así de largo.
Si simplemente dejar un comentario en contra de la opinión de otra persona fuera impedir su libertad de expresión, entonces también habría que considerar que crawler está vulnerando mi libertad de expresión en este momento. Si no es así, ¿no sería lógicamente una doble vara?

Y, como también reconoció crawler, al final si fue abuso o no no era en absoluto importante dentro del criterio de evaluación.
¿No contradice eso lo que dijiste de que "como dije ayer, si no hubiera sido marcado con flags yo también habría estado de acuerdo, pero desde el momento en que manipuló las recomendaciones de lo que escribió, esta discusión deja de tener sentido"?
Parece que el punto y la postura siguen cambiando, así que me gustaría que los fijaras en una sola cosa.

 
kunggom 2026-01-20

Creo que actuar de forma colectiva para condenar un texto diciendo "este artículo no está a la altura de nuestra comunidad", cuando sí tiene suficiente relación con el tema de la comunidad y no es contenido generado por IA de baja calidad, quizá sea incluso más perjudicial para el crecimiento y la continuidad de la comunidad que la manipulación de votos. Esto puede hacer que la imagen pública de esa comunidad se vea excluyente y, como resultado, puede obstaculizar mucho la llegada de nuevos usuarios potenciales.

Por supuesto, no estoy diciendo que no se deba criticar. Pero al menos me parece que este ambiente es un poco extraño. En general, lo que se veía era decepción porque no era el tipo de contenido que esperaban, y hubo muy pocos análisis o comentarios que parecieran constructivos.

Y si de verdad creen que es un problema que alguien a quien se le detectó abuso vuelva a publicar al día siguiente, ¿por qué no aprovechan esta oportunidad para proponer formalmente al equipo de moderación que agregue una regla al respecto? Según entiendo, ya existe cierto nivel de sanción, pero parece que consideran que no es suficiente.

 
ifmkl 2026-01-20

Yo, al contrario, más bien no lo entiendo. ¿Lo están viendo como si esto se hubiera publicado para criticar en grupo y de forma organizada? Su postura, de hecho, me parece que está llevando de manera negativa las opiniones que cada persona puede expresar por su cuenta. En adelante, espero que también miren con la misma calidez publicaciones que sean más bien como un diario de desarrollo (¡me fijé una meta para mejorar el dibujo de estrellas con printf, lo optimicé y por eso usé un bucle for!).

 
bandcrownie 2026-01-20

Parece que usted también se promocionaba seguido en galerías de otros sitios, como con Era de los Seis Dragones o Web Sangokumusoujeon.
Al ver la actitud de presentar sus trabajos inconclusos solo para tantear el terreno y luego abandonar fácilmente esos proyectos, me pregunto en qué se diferencia eso de lo que critica en esta publicación... ¿por qué aplica un criterio tan estricto a los demás?

¿Será que como DC Inside es un lugar donde juegan niños, da igual hacer lo que sea, pero como GeekNews es un sitio al que usted le tiene cariño, no puede tolerar que alguien más lo ensucie?

No es que quiera argumentarlo de forma lógica; solo lo digo porque me parece curioso ese doble estándar, así que si quiere refutarme, tiene razón. Ánimo con el abuso.

 
tensun 2026-01-20

Se presenta la API de autocompletado de búsqueda como si fuera un servicio optimizado, pero por el título y el contenido al final solo parece optimización de búsquedas en la base de datos.
Si es para uso comercial, con optimización en Oracle basta, y ya existen muchos servicios de autocompletado. Tampoco habla de ningún diferenciador, y el contenido está al nivel de un ejercicio personal.
La verdad, resulta bastante incómodo de ver.