Яндекс продолжает банить ссылкообменники и SEO

Новая новость от Яндекса, что теперь они будут банить сайты за продажу ссылок. До этого они начали банить сайты за покупку входящих ссылок. Такими темпами Яндекс вообще может предложить отказаться от ссылок. Зачем сейчас в интернете ссылки, когда все пользуются мобильными приложениями? В этом же направлении движется и Google, который постепенно увеличивает ранк для сайтов, у которых есть мобильная версия или мобильное приложение.

А в итоге этим поисковикам пора бы закончить дурить головы веб-мастерам и ввести ранжирование сайтов на платной основе. Те сайты, у которых установлены банеры от поисковика (Yandex.Direct и Google.AdSense - соответственно) ранжировать по величине прибыли для поисковика. Чем больше денег приносит, тем выше. Хотя это и так есть в поисковиках - покупка ключевых слов.


Метки: , ,   Категории:Yandex | Google


.Net - Контексный поиск с учетом русской и английской морфологии

Подведу итог моим экспериментам с библиотекой Lucene.Net, под катом немало кода.

Для чего это: Поиск документов по словам с учетом морфологических модификаций в большой базе документов
Программный язык: CSharp.
Потрачено времени: Двое суток
Использованные продукты: MSVS, Lucene.Net, Lemmanizer с дополнительным английским словарем.
Ограничения и лицензии: Apache2.0 для Lucene и 250y.e. за Lemmanizer или бесплатная демо до конца года.
Дополнительно: Немало полезного есть на CodeProject, а также пример простого поиска описывали в RSDN

Начну с результатов
1) Индекс на 1530 текстовых документов занял 40минут, и 1,4мегабайта на диске. Если отключить морфологию, то те же действия выполняются за 1 минуту.
2) Иллюстрация поиска, который выполняется почти моментально

Видно, что по слову authority и authorities найдено одинаковое число документов, при отключении морфологии их число разнится
Одинаковое число документов для Бандитко и Чичваркина вызвано тем, что в xml настройке для SynonymFilter я указал эти слова в качестве синонимов.


Итак, наша задача при написании контекстного поиска с учетом морфологии с использованием Lucene.Net сводиться к описанию класса по разбору текста и вставлению в него всех слов, которые как-то коррелируют с текущим. Я написал следующий класс
Copy Source | Copy HTML
  1. namespace Lucene.Net.Analysis.Morphology
  2. {
  3.     using System;
  4.     using System.Data;
  5.     using System.Configuration;
  6.     using System.Web;
  7.     using System.IO;
  8.     using System.Web.Security;
  9.     using System.Web.UI;
  10.     using System.Web.UI.WebControls;
  11.     using System.Web.UI.WebControls.WebParts;
  12.     using System.Web.UI.HtmlControls;
  13.     using Lucene.Net.Analysis.Standard;
  14.     using Lucene.Net.SynonymEngine;
  15.  
  16.     /// <summary>
  17.     /// Анализатор текста для Lucene.Net с использованием морфологического анализа и словаря синонимов
  18.     /// </summary>
  19.     public class MorphologyAnalyzer : Analyzer
  20.     {
  21.         public MorphologyAnalyzer(ISynonymEngine engine)
  22.         {
  23.             //запомнили откуда брать синонимы
  24.             SynonymEngine = engine;
  25.             isSearchQuery = false;
  26.             //грузим словари
  27.             Morph = new MorphENRU();
  28.         }
  29.  
  30.         private MorphENRU Morph;
  31.         private ISynonymEngine _SynonymEngine;
  32.         private Boolean isSearchQuery;
  33.  
  34.         /// <summary>
  35.         /// Объект для перечисления синонимов слова
  36.         /// </summary>
  37.         public ISynonymEngine SynonymEngine {
  38.             get {
  39.                 return _SynonymEngine;
  40.             }
  41.             private set
  42.             {
  43.                 _SynonymEngine = value;
  44.             }
  45.         }
  46.  
  47.         /// <summary>
  48.         /// Выключаем проверку синонимов
  49.         /// </summary>
  50.         /// <returns></returns>
  51.         public MorphologyAnalyzer SetQuerySynonym()
  52.         {
  53.             this.isSearchQuery = true;
  54.             return this;
  55.         }
  56.  
  57.         /// <summary>
  58.         /// Анализуем текст и возвращаем в виде нобора слов для помещения в индекс и подсчета частот
  59.         /// </summary>
  60.         /// <param name="fieldName">Имя индексируемого файла</param>
  61.         /// <param name="reader">Поток для чтнения файла</param>
  62.         /// <returns>TokenStream</returns>
  63.         public override TokenStream TokenStream(string fieldName, TextReader reader)
  64.         {
  65.             //создаем обход слов
  66.             TokenStream result = new StandardTokenizer(reader);
  67.  
  68.             //преобразуем исходную строчку
  69.             result = new StandardFilter(result); // выделение слов при помощи StandardTokenizer
  70.             result = new LowerCaseFilter(result);// Приведение к нижнему регистру
  71.  
  72.             // простой фильтр английских местоимений,
  73.             // русских, к сожалению нету
  74.             result = new StopFilter(result, StopAnalyzer.ENGLISH_STOP_WORDS);
  75.             result = new MorphFilter(result, Morph); // вставляем морфологическую модификацию
  76.             result = new SynonymFilter(result, SynonymEngine, this.isSearchQuery); // вставляем синонимы
  77.  
  78.             //возвращаем набор токенов для помещения в индекс
  79.             return result;
  80.         }
  81.     }
  82.  
  83. }

Видно, что кроме стандартных фильтров, я добавил MorphFilter - вставка морфологических модификаций и SynonymFilter - для вставки синонимов. Класс MorphENRU используется для работы со словарями морфологии на базе библиотеки Lemmanizer и идет ниже
Copy Source | Copy HTML
  1. namespace Lucene.Net.Analysis.Morphology
  2. {
  3.     using LEMMATIZERLib;//морфология
  4.     using System;
  5.     using System.Collections.Generic;
  6.     using System.Configuration;
  7.     using System.Data;
  8.     using System.Diagnostics;
  9.     using System.IO;
  10.     using System.Text;
  11.     using System.Text.RegularExpressions;
  12.     using System.Web;
  13.     using System.Web.Security;
  14.     using System.Web.UI;
  15.     using System.Web.UI.WebControls;
  16.     using System.Web.UI.WebControls.WebParts;
  17.     using System.Web.UI.HtmlControls;
  18.  
  19.     /// <summary>
  20.     /// Работа с морфологией для анг. и русского языка
  21.     /// </summary>
  22.     public class MorphENRU
  23.     {
  24.         /// <summary>
  25.         /// Регулярное выражение для определения английских слов
  26.         /// </summary>
  27.         private Regex rWordEn = new Regex(@"[a-z0-9]+", RegexOptions.Singleline | RegexOptions.Compiled
  28.             | RegexOptions.ExplicitCapture);
  29.  
  30.         /// <summary>Анализатор английских слов</summary>
  31.         private ILemmatizer Lemmatizer_en;
  32.  
  33.         /// <summary>
  34.         /// Анализатор русских слов
  35.         /// </summary>
  36.         private ILemmatizer Lemmatizer_ru;
  37.  
  38.  
  39.         public MorphENRU()
  40.         {
  41.             //в конструкторе нужно загрузить морфологию
  42.             try
  43.             {
  44.                 Lemmatizer_ru = new LemmatizerRussianClass();
  45.                 Lemmatizer_ru.LoadDictionariesRegistry();
  46.                 Lemmatizer_en = new LemmatizerEnglishClass();
  47.                 Lemmatizer_en.LoadDictionariesRegistry();
  48.                 Debug.WriteLine("Загрузка морфологи успешно завершена.");
  49.             }
  50.             catch (Exception e)
  51.             {
  52.                 Debug.WriteLine("Ошибка при открытиии морфологического словаря: " + e.Message);
  53.                 //ошибка может быть по многим причинам - например,
  54.                 //кто-то удалил файлы словарей или истекла лицензия,
  55.                 //тогда игнорируем морфологию
  56.                 Lemmatizer_ru = null;
  57.                 Lemmatizer_en = null;
  58.             }
  59.         }
  60.  
  61.         /// <summary>
  62.         /// Делаем слово морфологически инвариантным
  63.         /// </summary>
  64.         /// <param name="word"></param>
  65.         /// <returns></returns>
  66.         public List<string> NormalizeWord(string word)
  67.         {
  68.             List<string> WordList = null;
  69.             if (Lemmatizer_ru != null &&
  70.     Lemmatizer_en != null)
  71.             {
  72.                 //если ошибка в словарях, то пропускаем обработку
  73.                 int weight = -1;
  74.                 bool isEng = this.rWordEn.Match(word).Success;//английское или русское слово
  75.                 // ищем варианты в словаре
  76.                 IParadigmCollection ParadigmCollection =
  77.                     isEng ?
  78.                     Lemmatizer_en.CreateParadigmCollectionFromForm(word, 1, 1) :
  79.                     Lemmatizer_ru.CreateParadigmCollectionFromForm(word, 1, 1);
  80.                 // выбираем наиболее тяжелое по весу
  81.                 for (int j = 0; j < ParadigmCollection.Count; j++)
  82.                 {
  83.                     if (ParadigmCollection[j].WordWeight > weight)
  84.                     {
  85.                         if (ParadigmCollection[j].Norm == "ДЛИТЬ") continue;
  86.                         //будем брать всего одно самое весовое слово для морфологии
  87.                         if (WordList == null)
  88.                         {
  89.                             WordList = new List<string>();
  90.                             WordList.Add(ParadigmCollection[j].Norm.ToLower());
  91.                         }
  92.                         else
  93.                         {
  94.                             WordList[0] = ParadigmCollection[j].Norm.ToLower();
  95.                         }
  96.                         weight = ParadigmCollection[j].WordWeight;
  97.                         //графемы нам не нужны
  98.                         //gramma = this.ParadigmCollection[j].SrcAncode;
  99.                     }
  100.                 }
  101.             }
  102.             return WordList;
  103.         }
  104.     }
  105. }


В функции NormalizeWord видно, что для каждого слова мы берем только ту его морфологическую модификацию, которая имеет наибольший вес. Можно было бы брать больше слов, но тогда размер индекса сильно бы увеличился. Кроме того, на этапе фильтра MorphFilter мы игнорируем все слова с длинною меньше 4х символов, чтобы ускорить работу. Сам класс MorphFilter приведен ниже
Copy Source | Copy HTML
  1. namespace Lucene.Net.Analysis.Morphology
  2. {
  3.     using System;
  4.     using System.Data;
  5.     using System.Configuration;
  6.     using System.Collections.Generic;
  7.     using System.Web;
  8.     using System.Web.Security;
  9.     using System.Web.UI;
  10.     using System.Web.UI.WebControls;
  11.     using System.Web.UI.WebControls.WebParts;
  12.     using System.Web.UI.HtmlControls;
  13.     using Lucene.Net.Analysis;
  14.  
  15.     /// <summary>
  16.     /// Обход набора слов и вставка морфологических модификаций
  17.     /// </summary>
  18.     public class MorphFilter : TokenFilter
  19.     {
  20.         private Queue<Token> morphTokenQueue
  21.             = new Queue<Token>();
  22.  
  23.         private MorphENRU _MorphEngine;
  24.         public MorphENRU MorphEngine { get { return _MorphEngine; } private set { _MorphEngine = value; } }
  25.  
  26.         public MorphFilter(TokenStream input, MorphENRU morphEngine)
  27.             : base(input)
  28.         {
  29.             if (morphEngine == null)
  30.                 throw new ArgumentNullException("morphEngine");
  31.  
  32.             MorphEngine = morphEngine;
  33.         }
  34.  
  35.         public override Token Next()
  36.         {
  37.             // Если есть слова в очереди, то надо их поместить в поток прежде чем одти дальше
  38.             if (morphTokenQueue.Count > 0)
  39.             {
  40.                 return morphTokenQueue.Dequeue();
  41.             }
  42.  
  43.             //Берем след. слово из текста
  44.             Token t = input.Next();
  45.  
  46.             //если пусто, то конец потока
  47.             if (t == null)
  48.                 return null;
  49.  
  50.             //разбор морфологии только для слов длинною более 4х символов
  51.             if (t.TermText().Length > 4)
  52.             {
  53.  
  54.                 //получение актуальных морфологий
  55.                 IEnumerable<string> mWords = MorphEngine.NormalizeWord(t.TermText());
  56.  
  57.                 //если нет слов то вернем слово просто
  58.                 if (mWords != null)
  59.                 {
  60.                     //Переберем все морфологические формы которые более употребляемы
  61.                     foreach (string word in mWords)
  62.                     {
  63.                         //убедимся, что не дублируем слово
  64.                         if (!t.TermText().Equals(word))
  65.                         {
  66.                             //делаем морфологический токен
  67.                             Token mToken = new Token(word, t.StartOffset(), t.EndOffset(), "<MORPH>");
  68.  
  69.                             // устанавливаем относительное смещение в 0,
  70.                             // это нужно, чтобы отразить то, что добавляемое слово соответствует
  71.                             // старому месту в изначальном тексте
  72.                             mToken.SetPositionIncrement(0);
  73.  
  74.                             //помещаем в очередь на помещение в поток
  75.                             morphTokenQueue.Enqueue(mToken);
  76.                         }
  77.                     }
  78.                 }
  79.             }
  80.             //
  81.             return t;
  82.         }
  83.     }
  84.  
  85. }
Теперь можно использовать объект MorphologyAnalyzer в качестве аргумента для стандартных функций индексации и поиска Lucene.Net библиотеки. Пример, стандартного использования Lucene.Net находится по ссылке на RSDN в начале поста.


Метки: , ,   Категории:Csharp | Code


Кто я?

Программист. Я слежу за блогосферой и знаю, как будет развиваться интернет. Когда у меня есть время я даже прилагаю для этого усилия. Подробнее

Последние комментарии

Topbot at FeedsBurner

Мои Твиты

Twitter сентября 24, 19:17
@SielenaSemper по какой причине эта трансляция более недоступна?

Twitter сентября 23, 14:26
Разбор сериала "Конец детства" http://dlvr.it/Ppxjly https://twitter.com/f1ashr/status/911597559604420608/photo/1

Twitter сентября 22, 17:41
Спустя 18 лет в ЖЖ запустили поиск по постам http://dlvr.it/PpmtD1

Twitter сентября 22, 16:01
Интернет ищет инопланетян (экзопланеты) http://dlvr.it/PpltJF

Twitter сентября 22, 16:01
dlvrit вводит лимиты http://dlvr.it/PpltJf

Twitter сентября 22, 14:24
Iron Sky 3 - новый трейлер на 9 мая http://dlvr.it/PpkrvS https://twitter.com/f1ashr/status/911234743747805184/photo/1

Twitter сентября 22, 14:24
Про терракты в Лондоне http://dlvr.it/Ppkrv7

Twitter сентября 22, 14:24
Коломенский кремль: Альтернативная история http://dlvr.it/Ppkrrx https://twitter.com/f1ashr/status/911234723476676608/photo/1

Twitter сентября 22, 14:24
Паштет из мяса медведя с брусникой http://dlvr.it/PpkrcB https://twitter.com/f1ashr/status/911234712026234882/photo/1

Twitter сентября 22, 14:24
Рейтинг каналов и ботов Телеграмм http://dlvr.it/PpkrQw https://twitter.com/f1ashr/status/911234670553063424/photo/1

Twitter сентября 22, 14:24
Facebook опять забанил http://dlvr.it/PpkrPG

Twitter сентября 22, 14:24
Звездные войны Изгой Один http://dlvr.it/PpkrDL https://twitter.com/f1ashr/status/911234655310905344/photo/1

Twitter сентября 21, 15:26
Робот играющий в гольф http://dlvr.it/PpWS1G

Twitter сентября 21, 14:53
Мобильное приложение t30p.ru в AppStore http://dlvr.it/PpW5Qk

Twitter сентября 21, 14:53
Что будет 22 сентября? http://dlvr.it/PpW5Lb https://twitter.com/f1ashr/status/910879685042618368/photo/1

Twitter сентября 21, 14:20
Битва за Мосул в 360 с вертолета http://dlvr.it/PpVlXD https://twitter.com/f1ashr/status/910871392970608640/photo/1

Twitter сентября 21, 14:20
Очередной летающий электро-автомобиль http://dlvr.it/PpVlWl https://twitter.com/f1ashr/status/910871386507186177/photo/1

Twitter сентября 21, 14:20
Яндекс атаковал Израиль http://dlvr.it/PpVlX9

Twitter сентября 21, 14:20
Мелькает число 35 в международных новостях http://dlvr.it/PpVlWZ

Twitter сентября 21, 14:20
Информационные аккаунты в Твиттере http://dlvr.it/PpVlWF

Мой твиттер

Копирайт

Все мысли, высказанные в блоге, являются моим мнением и за это мнение меня никто не забанит! Кроме того, никто не имеет право копировать материалы блога без использования ctrl+C/V!

© Copyright 2008