Extend Solr search: content coverage, 14.0.2, news recency, result images

- Index the text columns of the market/solution Content Blocks and the
  vitec_items/vitec_faq_items collection children; story documents now
  include their body (inline tt_content children via
  tx_vitec_usecase_content, same per-element extraction as pages) -
  stories were indexed with subtitle and teaser only until now
- Upgrade EXT:solr 14.0.0-RC1 -> 14.0.2 final (the Solr image moved to a
  fresh volume because the configset changed; synonyms restored via REST)
- News decay with age by publication date: crdate is the import date, so
  news map datetime to created; boost function gated to news only
- Results carry `image`: processed 640px tile image per type,
  root-relative, null for pages and downloads
- Spec v1.21: 7.16 states the /_json prefix and lists `solution` in the
  type vocabulary; footer had been stuck at v1.19
- suggest-demo.html fetches through /_json after the URL swap
This commit is contained in:
orasche committed 2026-10-07 16:22:50 +02:00
1 parent 8e67f5db23
commit 9b1ad202a9
7 files changed
+242 -23

No files matched your search

@@ -394,6 +394,67 @@ plugin.tx_solr.index.queue.pages.fields {
40 = TEXT
40.field = vitec_quote
40.noTrimWrap = || |
# Content Blocks with their own text columns (market/solution
# templates, flip cards) - the workbook imports fill these
50 = TEXT
50.field = vitec_subline
50.noTrimWrap = || |
60 = TEXT
60.field = vitec_intro_headline
60.noTrimWrap = || |
70 = TEXT
70.field = vitec_intro_text
70.noTrimWrap = || |
80 = TEXT
80.field = vitec_text1
80.noTrimWrap = || |
90 = TEXT
90.field = vitec_text2
90.noTrimWrap = || |
100 = TEXT
100.field = vitec_back_text
100.noTrimWrap = || |
110 = TEXT
110.field = vitec_quote_position
110.noTrimWrap = || |
# Content Blocks collection children (cards, icon lists,
# FAQ) live in their own tables, keyed on the parent uid
120 = CONTENT
120 {
table = vitec_items
select {
pidInList.field = pid
where.dataWrap = {#foreign_table_parent_uid} = {field:uid}
orderBy = sorting
}
renderObj = COA
renderObj {
10 = TEXT
10.field = headline
10.noTrimWrap = || |
20 = TEXT
20.field = text
20.noTrimWrap = || |
}
}
130 = CONTENT
130 {
table = vitec_faq_items
select {
pidInList.field = pid
where.dataWrap = {#foreign_table_parent_uid} = {field:uid}
orderBy = sorting
}
renderObj = COA
renderObj {
10 = TEXT
10.field = question
10.noTrimWrap = || |
20 = TEXT
20.field = answer
20.noTrimWrap = || |
}
}
}
}
}
@@ -419,6 +480,37 @@ plugin.tx_solr.index.queue {
products = 1
products {
# result tile image: first reference, processed to 640px width
fields.image = FILES
fields.image {
references {
table = tx_vitec_domain_model_product
uid.data = field:uid
fieldName = image
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
stdWrap.ifEmpty.cObject = FILES
stdWrap.ifEmpty.cObject {
references {
table = tx_vitec_domain_model_product
uid.data = field:uid
fieldName = productimage
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
}
# sys_category titles - feeds the category facet
fields.category_stringM = SOLR_RELATION
fields.category_stringM {
@@ -470,6 +562,22 @@ plugin.tx_solr.index.queue {
markets = 1
markets {
# result tile image: first reference, processed to 640px width
fields.image = FILES
fields.image {
references {
table = tx_vitec_domain_model_market
uid.data = field:uid
fieldName = image
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
type = tx_vitec_domain_model_market
# only markets with an editorially assigned detail page are linkable;
# grows automatically as editors fill the field (4 of 34 right now)
@@ -503,6 +611,37 @@ plugin.tx_solr.index.queue {
usecases = 1
usecases {
# result tile image: first reference, processed to 640px width
fields.image = FILES
fields.image {
references {
table = tx_vitec_domain_model_usecase
uid.data = field:uid
fieldName = card_image
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
stdWrap.ifEmpty.cObject = FILES
stdWrap.ifEmpty.cObject {
references {
table = tx_vitec_domain_model_usecase
uid.data = field:uid
fieldName = hero_bgimage
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
}
# market titles from the MM relation - feeds the market facet
fields.market_stringM = SOLR_RELATION
fields.market_stringM {
@@ -524,6 +663,18 @@ plugin.tx_solr.index.queue {
20 = TEXT
20.field = teaser
20.noTrimWrap = || |
# the story body: inline tt_content children (text, columns,
# quotations) - same per-element extraction as page content
30 = CONTENT
30 {
table = tt_content
select {
pidInList.field = pid
where.dataWrap = {#tx_vitec_usecase_content} = {field:uid}
orderBy = sorting
}
renderObj < plugin.tx_solr.index.queue.pages.fields.content.cObject.10.renderObj
}
}
}
url = TEXT
@@ -544,6 +695,22 @@ plugin.tx_solr.index.queue {
# 39 records a detail_page (and slug). Same pattern as markets.
solutions = 1
solutions {
# result tile image: first reference, processed to 640px width
fields.image = FILES
fields.image {
references {
table = tx_vitec_domain_model_solution
uid.data = field:uid
fieldName = image
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
type = tx_vitec_domain_model_solution
additionalWhereClause = detail_page > 0
fields {
@@ -575,6 +742,25 @@ plugin.tx_solr.index.queue {
news = 1
news {
# crdate is the IMPORT date (Jul/Aug 2026) - the publication date
# lives in datetime. `created` feeds the news recency boost.
fields.created = datetime
# result tile image: first reference, processed to 640px width
fields.image = FILES
fields.image {
references {
table = tx_news_domain_model_news
uid.data = field:uid
fieldName = fal_media
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
type = tx_news_domain_model_news
# type 1 ("page as news") points at pages that are already indexed as
# pages - indexing them again would duplicate every one of them
@@ -707,3 +893,9 @@ plugin.tx_solr.suggest {
# type and the full indexed content - too fat and off-contract for type-ahead
showTopResults = 0
}
# News recency: old news decays against everything else. Additive edismax
# boost (bf): non-news documents get the constant 10, news get
# recip(age) = 10 when new, ~5 after one year, ~0.7 after 13 years.
# The gate keeps products/pages/stories out of the decay entirely.
plugin.tx_solr.search.query.boostFunction = if(termfreq(type,'tx_news_domain_model_news'),recip(ms(NOW,created),3.16e-11,10,1),10)