1- package com .github .oeuvres .alix .web . op ;
1+ package com .github .oeuvres .alix .web ;
22
33import java .io .IOException ;
44import java .util .List ;
88import jakarta .servlet .http .HttpServletRequest ;
99import jakarta .servlet .http .HttpServletResponse ;
1010
11+ import com .github .oeuvres .alix .lucene .FlucText ;
1112import com .github .oeuvres .alix .lucene .LuceneIndex ;
1213import com .github .oeuvres .alix .lucene .terms .TermRow ;
1314import com .github .oeuvres .alix .lucene .terms .TermScorer ;
1415import com .github .oeuvres .alix .lucene .terms .ThemeTerms ;
15- import com .github .oeuvres .alix .web .AlixServlet ;
1616
1717/**
1818 * {@code /{index}/terms} — ranked term lists.
3737 */
3838public final class OpTerms extends Op
3939{
40+ /** Clamping range for the {@code top} parameter. */
41+ private static final int [] TOP_RANGE = { 1 , 500 };
42+
4043 /** Default number of returned terms. */
4144 private static final int DEFAULT_TOP = 50 ;
4245
43- /** Hard ceiling on returned terms. */
44- private static final int MAX_TOP = 500 ;
45-
4646 /** Default BM25 IDF exponent. */
4747 private static final double DEFAULT_IDF_EXP = 1.3d ;
4848
@@ -56,10 +56,11 @@ protected void json(
5656 final HttpServletResponse resp
5757 ) throws IOException
5858 {
59- // ---- parameter parsing ----
60- final String field = fieldParam (index , req );
61- final int topK = topParam (req );
62- final String q = qParam (req );
59+ final HttpPars pars = new HttpPars (req );
60+
61+ final String field = pars .getString ("field" , index .content ());
62+ final int topK = pars .getInt ("top" , TOP_RANGE , DEFAULT_TOP );
63+ final String q = pars .getString ("q" , null );
6364
6465 // ---- dispatch to producer ----
6566 final List <TermRow > rows ;
@@ -72,88 +73,35 @@ protected void json(
7273 }
7374 else {
7475 // Theme terms mode
75- final ThemeTerms themeTerms = index .themeTerms (field );
76+ final FlucText fluc = index .fieldText (field );
77+ if (fluc == null ) {
78+ AlixServlet .sendError (resp , 404 ,
79+ "terms: field '" + field + "' not found or not a text field" );
80+ return ;
81+ }
82+ final ThemeTerms themeTerms = fluc .themeTerms ();
7683 if (themeTerms == null ) {
7784 AlixServlet .sendError (resp , 503 ,
7885 "terms: lexicon or field statistics not available for field '"
7986 + field + "'" );
8087 return ;
8188 }
82- final double idfExp = doubleParam ( req , "idfExp" , DEFAULT_IDF_EXP );
89+ final double idfExp = pars . getDouble ( "idfExp" , DEFAULT_IDF_EXP );
8390 final TermScorer scorer = new TermScorer .BM25 (idfExp );
8491 rows = themeTerms .topTerms (scorer , topK );
8592 }
8693
8794 // ---- serialize ----
88- writeTermRows (resp , rows );
89- }
90-
91- // ================================================================
92- // Serialization
93- // ================================================================
94-
95- /**
96- * Write a list of term rows as a JSON array.
97- */
98- private static void writeTermRows (
99- final HttpServletResponse resp ,
100- final List <TermRow > rows
101- ) throws IOException
102- {
103- final JsonWriter jw = jsonWriter (resp );
104- jw .beginArray ();
105- for (TermRow row : rows ) {
106- jw .beginObject ();
107- jw .name ("term" ).value (row .term ());
108- jw .name ("count" ).value (row .count ());
109- jw .name ("score" ).value (row .score ());
110- jw .endObject ();
111- }
112- jw .endArray ();
113- jw .flush ();
114- }
115-
116- // ================================================================
117- // Parameter helpers
118- // ================================================================
119-
120- /**
121- * Resolve the target field: explicit {@code field} param, or index default.
122- */
123- private static String fieldParam (
124- final LuceneIndex index ,
125- final HttpServletRequest req
126- ) {
127- final String param = req .getParameter ("field" );
128- if (param != null && !param .isBlank ()) {
129- return param .trim ();
130- }
131- return index .content ();
132- }
133-
134- /**
135- * Read the {@code top} parameter, clamped to {@code [1, MAX_TOP]}.
136- */
137- private static int topParam (final HttpServletRequest req )
138- {
139- return Math .max (1 , Math .min (intParam (req , "top" , DEFAULT_TOP ), MAX_TOP ));
140- }
141-
142- /**
143- * Read a double parameter, or {@code def} if absent/unparseable.
144- */
145- private static double doubleParam (
146- final HttpServletRequest req ,
147- final String name ,
148- final double def
149- ) {
150- final String s = req .getParameter (name );
151- if (s == null ) return def ;
152- try {
153- return Double .parseDouble (s .trim ());
154- }
155- catch (NumberFormatException e ) {
156- return def ;
95+ try (JsonWriter jw = jsonWriter (resp )) {
96+ jw .beginArray ();
97+ for (TermRow row : rows ) {
98+ jw .beginObject ();
99+ jw .name ("term" ).value (row .term ());
100+ jw .name ("count" ).value (row .count ());
101+ jw .name ("score" ).value (row .score ());
102+ jw .endObject ();
103+ }
104+ jw .endArray ();
157105 }
158106 }
159107}
0 commit comments