Внедрить класс 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);
Обратите внимание: существует потенциальное столкновение имен свойств и имен ключей словарь.
На самом деле использование оператора выбора для создания пары флагов могло бы быть лучшим решением:
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
Снова, это - то, только если все соответствия ключевого слова занимают место выше, чем все соответствия только для содержания. Я также сделал предположение, что соответствие и в ключевом слове и в содержании является самым высоким разрядом.
Я сделал это несколько лет назад, но без полнотекстового индекса. У меня нет кода удобным (бывший работодатель), но я помню технику хорошо.
, Короче говоря я выбрал "вес" из каждого столбца. Например:
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
Насколько я знаю, это не поддерживается с полнотекстовым поиском MySQL, но можно достигнуть эффекта, так или иначе повторяя что слово несколько раз в поле ключевого слова. Вместо того, чтобы иметь ключевые слова "панель нечто", имейте "панель нечто панели нечто панели нечто", тот путь и нечто и панель одинаково важны в столбце ключевых слов, и так как они несколько раз появляются, они становятся более относящимися к mysql.
Мы используем это на нашем сайте, и он работает.
Если метрика просто, что все соответствия ключевого слова более "ценны", чем все соответствия содержания затем, можно просто использовать объединение с количествами строки. Что-то вдоль этих строк.
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
Для чего-либо более сложного, чем это, где Вы хотите применить фактический вес до каждой строки, я не знаю, как помочь.
Ну, это зависит от того, что делает Вас, точно означают с:
я хочу, чтобы строка с нечто в ключевых словах имела больше уместности, чем строка с нечто в содержании.
, Если Вы подразумеваете, что строка с нечто в ключевых словах должна прибыть прежде любой строка с нечто в содержании, затем я сделаю два отдельных запроса, один для ключевых слов и затем (возможно лениво, только если это требуют), другой на содержании.
Создайте три полнотекстовых индекса
Затем Ваш запрос:
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, но это довольно легко и "из поля", и это - почти наверняка много партии лучше, чем Ваше использование "подобных" в запросах.
Я нахожу, что это работает действительно хорошо.
В логическом режиме 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