Как я могу управлять уместностью полнотекстового поиска MySQL для создания одного поля более 'ценным', чем другой?

Внедрить класс JsonConverter : класс CustomCreationConverter должен использоваться как базовый класс для создания пользовательского объекта.

Черновик версии конвертера (обработка ошибок может быть улучшена по вашему желанию):

internal class TestObjectConverter : CustomCreationConverter
{
    #region Overrides of CustomCreationConverter

    public override Test Create(Type objectType)
    {
        return new Test
            {
                Y = new Dictionary()
            };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartObject();

        // Write properties.
        var propertyInfos = value.GetType().GetProperties();
        foreach (var propertyInfo in propertyInfos)
        {
            // Skip the Y property.
            if (propertyInfo.Name == "Y")
                continue;

            writer.WritePropertyName(propertyInfo.Name);
            var propertyValue = propertyInfo.GetValue(value);
            serializer.Serialize(writer, propertyValue);
        }

        // Write dictionary key-value pairs.
        var test = (Test)value;
        foreach (var kvp in test.Y)
        {
            writer.WritePropertyName(kvp.Key);
            serializer.Serialize(writer, kvp.Value);
        }
        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jsonObject = JObject.Load(reader);
        var jsonProperties = jsonObject.Properties().ToList();
        var outputObject = Create(objectType);

        // Property name => property info dictionary (for fast lookup).
        var propertyNames = objectType.GetProperties().ToDictionary(pi => pi.Name, pi => pi);
        foreach (var jsonProperty in jsonProperties)
        {
            // If such property exists - use it.
            PropertyInfo targetProperty;
            if (propertyNames.TryGetValue(jsonProperty.Name, out targetProperty))
            {
                var propertyValue = jsonProperty.Value.ToObject(targetProperty.PropertyType);
                targetProperty.SetValue(outputObject, propertyValue, null);
            }
            else
            {
                // Otherwise - use the dictionary.
                outputObject.Y.Add(jsonProperty.Name, jsonProperty.Value.ToObject());
            }
        }

        return outputObject;
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    #endregion
}

Код клиента:

var test = new Test
    {
        X = "123",
        Y = new Dictionary
            {
                { "key1", "value1" },
                { "key2", "value2" },
                { "key3", "value3" },
            }
    };

string json = JsonConvert.SerializeObject(test, Formatting.Indented, new TestObjectConverter());
var deserializedObject = JsonConvert.DeserializeObject(json);

Обратите внимание: существует потенциальное столкновение имен свойств и имен ключей словарь.

37
задан Buzz 17 February 2009 в 22:16
поделиться

7 ответов

На самом деле использование оператора выбора для создания пары флагов могло бы быть лучшим решением:

select 
...
, case when keyword like '%' + @input + '%' then 1 else 0 end as keywordmatch
, case when content like '%' + @input + '%' then 1 else 0 end as contentmatch
-- or whatever check you use for the matching
from 
   ... 
   and here the rest of your usual matching query
   ... 
order by keywordmatch desc, contentmatch desc

Снова, это - то, только если все соответствия ключевого слова занимают место выше, чем все соответствия только для содержания. Я также сделал предположение, что соответствие и в ключевом слове и в содержании является самым высоким разрядом.

20
ответ дан notnot 23 September 2019 в 20:16
поделиться

Я сделал это несколько лет назад, но без полнотекстового индекса. У меня нет кода удобным (бывший работодатель), но я помню технику хорошо.

, Короче говоря я выбрал "вес" из каждого столбца. Например:

select table.id, keyword_relevance + content_relevance as relevance from table
   left join
      (select id, 1 as keyword_relevance from table_name where keyword match) a
   on table.id = a.id
   left join
      (select id, 0.75 as content_relevance from table_name where content match) b
   on table.id = b.id

простите любой дрянной SQL здесь, это были несколько лет, с тех пор как я должен был записать любому, и я делаю это первое, что пришло на ум...

Hope это помогает!

J.Js

0
ответ дан 23 September 2019 в 20:16
поделиться

Насколько я знаю, это не поддерживается с полнотекстовым поиском MySQL, но можно достигнуть эффекта, так или иначе повторяя что слово несколько раз в поле ключевого слова. Вместо того, чтобы иметь ключевые слова "панель нечто", имейте "панель нечто панели нечто панели нечто", тот путь и нечто и панель одинаково важны в столбце ключевых слов, и так как они несколько раз появляются, они становятся более относящимися к mysql.

Мы используем это на нашем сайте, и он работает.

0
ответ дан adamJLev 23 September 2019 в 20:16
поделиться

Если метрика просто, что все соответствия ключевого слова более "ценны", чем все соответствия содержания затем, можно просто использовать объединение с количествами строки. Что-то вдоль этих строк.

select *
from (
   select row_number() over(order by blahblah) as row, t.*
   from thetable t
   where keyword match

   union

   select row_number() over(order by blahblah) + @@rowcount + 1 as row, t.*
   from thetable t
   where content match
)
order by row

Для чего-либо более сложного, чем это, где Вы хотите применить фактический вес до каждой строки, я не знаю, как помочь.

-4
ответ дан notnot 23 September 2019 в 20:16
поделиться

Ну, это зависит от того, что делает Вас, точно означают с:

я хочу, чтобы строка с нечто в ключевых словах имела больше уместности, чем строка с нечто в содержании.

, Если Вы подразумеваете, что строка с нечто в ключевых словах должна прибыть прежде любой строка с нечто в содержании, затем я сделаю два отдельных запроса, один для ключевых слов и затем (возможно лениво, только если это требуют), другой на содержании.

-1
ответ дан Davide 23 September 2019 в 20:16
поделиться

Создайте три полнотекстовых индекса

  • a) один на столбце ключевого слова
  • b) один на столбце содержания
  • c) один и на ключевом слове и на столбце содержания

Затем Ваш запрос:

SELECT id, keyword, content,
  MATCH (keyword) AGAINST ('watermelon') AS rel1,
  MATCH (content) AGAINST ('watermelon') AS rel2
FROM table
WHERE MATCH (keyword,content) AGAINST ('watermelon')
ORDER BY (rel1*1.5)+(rel2) DESC

Дело в том, что rel1 придает Вам актуальность Вашего запроса только в keyword столбец (потому что Вы создали индекс только на том столбце). rel2 делает то же, но для content столбец. Можно теперь добавить эти два очков уместности, вместе применяющие любое взвешивание, Вам нравится.

Однако Вы не используете ни один из этих двух индексов для фактического поиска. Для этого Вы используете свой третий индекс, который находится на обоих столбцах.

Индекс на (ключевое слово, содержание) управляет Вашим отзывом. Иначе, что возвращается.

Два отдельных индекса (один на ключевом слове только, один только на содержании) управляют Вашей уместностью. И можно применить собственные критерии взвешивания здесь.

Обратите внимание, что можно использовать любое количество различных индексов (или, варьируйтесь индексы и коэффициенты, которые Вы используете во время запроса на основе других факторов, возможно..., только ищут на ключевом слове, если запрос содержит стоп-слово... уменьшают предвзятость взвешивания для ключевых слов, если запрос содержит больше чем 3 слова... и т.д.).

Каждый индекс действительно израсходовал дисковое пространство, так больше индексов, больше диска. И в свою очередь, более высокий объем потребляемой памяти для mysql. Кроме того, вставки займут больше времени, поскольку у Вас есть больше индексов для обновления.

Необходимо сравнить производительности (стараться еще выключают кэш запроса mysql для сравнительного тестирования результаты будут скошены) для ситуации. Это не эффективный класс Google, но это довольно легко и "из поля", и это - почти наверняка много партии лучше, чем Ваше использование "подобных" в запросах.

Я нахожу, что это работает действительно хорошо.

81
ответ дан Liam 27 November 2019 в 03:14
поделиться

В логическом режиме MySQL поддерживает операторы «>» и «<» для изменения вклада слова в значение релевантности, которое присваивается ряд.

Интересно, сработает ли что-то подобное?

SELECT *, 
MATCH (Keywords) AGAINST ('>watermelon' IN BOOLEAN MODE) AS relStrong, 
MATCH (Title,Keywords,Content) AGAINST ('<watermelon' IN BOOLEAN MODE) AS relWeak 
FROM about_data  
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
ORDER by (relStrong+relWeak) desc
0
ответ дан 27 November 2019 в 03:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: