Best search engine (RELEVANCE)
« on: November 10, 2025, 12:40:11 AM »
To achieve search/sort by "relevance," I looked at Mindstellar (available on GitHub), which, starting with version 5.0.0, stated in its changelog that, among other changes, it had included this feature. What I did was adapt the code in model/Search.php and helpers/hSearch.php (to include the option). Specifically, in the code within model/Search.php, I changed this section to:

 
Code: [Select]
/**
 * Establish the order of the search
 *
 * @access public
 * @since unknown
 * @param string $o_c column
 * @param string $o_d direction
 * @param string $table
 */
public function order($o_c = '', $o_d = 'DESC', $table = null)
{
    // LÓGICA DE RELEVANCIA MEJORADA:
    // 1. Si la columna de orden es 'relevance', la forzamos a ser descendente (la mayor puntuación es la más relevante).
    if ($o_c === 'relevance') {
        $o_d = 'DESC';
       
    // 2. Si no se ha especificado un orden ('') o el orden es el de defecto ('dt_pub_date')
    // y hay un patrón de búsqueda, forzamos 'relevance'.
    } elseif ($o_c === '') {
    if ($this->withPattern) {
        $o_c = 'relevance'; // Usar relevancia si hay patrón de búsqueda
        } else {
            $o_c = 'dt_pub_date'; // Usar fecha de publicación si no hay patrón
        }
    }
    // FIN DE LA LÓGICA DE RELEVANCIA

    // Lógica original de OsclassPoint para establecer la columna
    if ($table == '') {
        $this->order_column = $o_c;
       
    } elseif ($table != '') {
        // Nota: Adaptado para usar el prefijo de Osclass y la lógica de Mindstellar.
        if ($table === DB_TABLE_PREFIX . 't_user') {
            $this->order_column = sprintf("ISNULL(%s.$o_c), %s.$o_c", $table, $table);
        } else {
            $this->order_column = sprintf("$table.$o_c");
        }
    }

    $this->order_direction = $o_d;
}



and this:




Code: [Select]
/**
 * Return an array with columns allowed for sorting
 *
 * @return array
 */
public static function getAllowedColumnsForSorting($extended = false) {
    $data = array('i_price', 'dt_pub_date', 'relevance');
   
    if($extended === true) {
      $data[] = 'dt_expiration';
      $data[] = 'i_rating';
    }
   
    return osc_apply_filter('search_list_columns', $data);
}

I also modified this part as follows:

Code: [Select]
      if($this->withPattern) {
        // Unir la tabla de descripciones (ya existe en OsclassPoint)
        $this->dao->join(DB_TABLE_PREFIX.'t_item_description as d','d.fk_i_item_id = '.DB_TABLE_PREFIX.'t_item.pk_i_id','LEFT');

        // ********** INYECCIÓN DE LÓGICA DE RELEVANCIA **********
       
        // 1. Si se ordenó por relevancia, añadimos el SELECT y HAVING
        if ($this->order_column === 'relevance') {
            // SELECT: Añadir la columna de puntuación 'relevance' (Mindstellar)
            $this->dao->select(sprintf(
                                   "MATCH(d.s_title, d.s_description) AGAINST('%s') as relevance",
                                   $this->sPattern
                               ));
           
            // HAVING: Filtra los resultados con puntuación cero (Mindstellar)
            $this->dao->having(sprintf("relevance > %s", 0));
        }

        // ********** FIN DE INYECCIÓN DE LÓGICA DE RELEVANCIA **********

        $search_pattern_cond = '';
       
        // 2. Lógica de WHERE de OsclassPoint (Mantenida)
        if($this->sPattern != '') {
          if(osc_search_pattern_method() == '') {
            // Si la columna de orden es 'relevance', ya no necesitamos un WHERE adicional,
            // ya que el HAVING lo hace. De lo contrario, usamos BOOLEAN MODE.
            if ($this->order_column !== 'relevance') {
              $search_pattern_cond = sprintf("MATCH(d.s_title, d.s_description) AGAINST('%s' IN BOOLEAN MODE)", $this->sPattern);
            }
          } else if(osc_search_pattern_method() == 'nlp') {
            // Si el modo es NLP, no ordenamos, solo filtramos
            $search_pattern_cond = sprintf("MATCH(d.s_title, d.s_description) AGAINST('%s' IN NATURAL LANGUAGE MODE)", $this->sPattern);
           
          } else if(osc_search_pattern_method() == 'like') {
            $search_pattern_cond = sprintf("lower(concat(d.s_title, d.s_description)) like '%%%s%%'", strtolower(trim((string)$this->sPattern)));
          }
        }
       
        $search_pattern_cond = osc_apply_filter('search_cond_pattern', $search_pattern_cond, $this->sPattern);
       
        if($search_pattern_cond != '') {
          $this->dao->where($search_pattern_cond);
        }

        if(osc_search_pattern_current_locale_only()) {
          if(empty($this->locale_code)) {
            if(OC_ADMIN) {
              $this->locale_code[osc_current_admin_locale()] = osc_current_admin_locale();
            } else {
              $this->locale_code[osc_current_user_locale()] = osc_current_user_locale();
            }
          }
         
          $this->dao->where(sprintf("(d.fk_c_locale_code LIKE '%s')", implode("' d.fk_c_locale_code LIKE '", $this->locale_code)));
        }
      }



and in the helpers/hSearch.php file, I modified it as follows:

Code: [Select]
/**
 * Gets available search orders
 *
 * @return array
 */
function osc_list_orders() {
    $default_orders = array();

    // Si hay patrón de búsqueda, añadimos relevance como primera opción
    if (osc_search_pattern() !== '') {
        $default_orders[__('Relevance')] = array(
            'sOrder' => 'relevance',
            'iOrderType' => 'desc'
        );

        // *** TRUCO IMPORTANTE ***
        // Si el usuario no eligió un orden (GET vacío), fijamos relevance como orden activo
        if (Params::getParam('sOrder') === '') {
            Params::setParam('sOrder', 'relevance');
            Params::setParam('iOrderType', 'desc');
        }
    }

    // Lógica original de OsclassPoint
    $default_orders[__('Newly listed')] = array(
        'sOrder' => 'dt_pub_date',
        'iOrderType' => 'desc'
    );

    if (osc_price_enabled_at_items()) {
        $default_orders[__('Lower price first')] = array('sOrder' => 'i_price', 'iOrderType' => 'asc');
        $default_orders[__('Higher price first')] = array('sOrder' => 'i_price', 'iOrderType' => 'desc');
    }

    return osc_apply_filter('search_list_orders', $default_orders);
}

What I (personally) would like to do is (having already achieved the search/sort by "Relevance" (which works perfectly)) have the search logic look something like this: Relevance (First place) Relevance + Most recent (Second place) Relevance + Price: Cheapest (Third place) Relevance + Price: Most expensive (Fourth place) etc...
« Last Edit: November 14, 2025, 07:55:42 AM by Dani Rucabado »

*

MB Themes

Re: Best search engine (RELEVANCE)
« Reply #1 on: November 11, 2025, 10:31:40 AM »
There will be update in 8.3.1 that enable sort by relevance.
There is more issues related to current/older versions and that was that relevance column to sort by did not exists.
Way how it will work in 8.3.1 is:
- sort by relevance is only available when you fill search pattern (otherwise makes no sense)
- when sort by relevance selected, new column is added into select columns with name "relevance" that enable sorting by this field
- sort DESC by default
  To get fast support, we need following details: Detail description, URL to reproduce problem, Screenshots