Last active
February 5, 2018 10:18
-
-
Save elw00d/f27cf9fe6a8aad6b3761 to your computer and use it in GitHub Desktop.
SOLR custom token filter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ru.dz; | |
import org.apache.lucene.analysis.TokenFilter; | |
import org.apache.lucene.analysis.TokenStream; | |
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; | |
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; | |
import java.io.IOException; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Добавляет к каждому терму дубликат, записанный в другой раскладке. Регистр символов сохраняется. | |
* Например, на входе термы: Шзрщту, vfvf, папа | |
* На выходе: Шзрщту, Iphone, vfvf, мама, папа, gfgf | |
* * | |
* @author igor.kostromin | |
* 8/13/2014 | |
*/ | |
public class RusEnKeyboardLayoutFilter extends TokenFilter { | |
protected final char[] latins = {'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', | |
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', | |
'b', 'n', 'm', ',', '.'}; | |
protected final char[] cyrillics = {'й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', | |
'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', | |
'и', 'т', 'ь', 'б', 'ю'}; | |
private final Map<Character, Character> latin2cyrMap; | |
private final Map<Character, Character> cyr2latinMap; | |
private final PositionIncrementAttribute posIncAttr = addAttribute(PositionIncrementAttribute.class); | |
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); | |
private State state; | |
public RusEnKeyboardLayoutFilter(TokenStream input) { | |
super(input); | |
latin2cyrMap = new HashMap<>(); | |
cyr2latinMap = new HashMap<>(); | |
for (int i = 0; i < latins.length; i++) { | |
latin2cyrMap.put(latins[i], cyrillics[i]); | |
latin2cyrMap.put(Character.toUpperCase(latins[i]), Character.toUpperCase(cyrillics[i])); | |
cyr2latinMap.put(cyrillics[i], latins[i]); | |
cyr2latinMap.put(Character.toUpperCase(cyrillics[i]), Character.toUpperCase(latins[i])); | |
} | |
} | |
@Override | |
public boolean incrementToken() throws IOException { | |
if (state != null) { | |
restoreState(state); | |
// Этот вызов нужен для того, чтобы у оригинального терма не увеличивалась позиция | |
// Т.к. при каждом последующем вызове incrementToken() позиция увеличивается на единицу | |
// (см код KeywordRepeatFilter) | |
posIncAttr.setPositionIncrement(0); | |
state = null; | |
return true; | |
} | |
if (input.incrementToken()) { | |
state = captureState(); | |
// Переводим строку в другую раскладку | |
char[] buffer = termAtt.buffer(); | |
if (buffer.length > 0) { | |
for (int i = 0; i < buffer.length; i++) { | |
if (latin2cyrMap.containsKey(buffer[i])) | |
buffer[i] = latin2cyrMap.get(buffer[i]); | |
else if (cyr2latinMap.containsKey(buffer[i])) | |
buffer[i] = cyr2latinMap.get(buffer[i]); | |
} | |
} | |
return true; | |
} | |
return false; | |
} | |
@Override | |
public void reset() throws IOException { | |
super.reset(); | |
state = null; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package ru.dz; | |
import org.apache.lucene.analysis.TokenStream; | |
import org.apache.lucene.analysis.util.TokenFilterFactory; | |
import java.util.Map; | |
/** | |
* @author igor.kostromin | |
* 8/13/2014 | |
*/ | |
public class RusEnKeyboardLayoutFilterFactory extends TokenFilterFactory { | |
public RusEnKeyboardLayoutFilterFactory(Map<String, String> args) { | |
super(args); | |
} | |
@Override | |
public TokenStream create(TokenStream input) { | |
return new RusEnKeyboardLayoutFilter(input); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- piece of schema.xml --> | |
<fieldType name="text_ru" class="solr.TextField" positionIncrementGap="100"> | |
<analyzer type="index"> | |
<tokenizer class="solr.StandardTokenizerFactory"/> | |
<filter class="solr.LowerCaseFilterFactory"/> | |
<!-- Чтобы оригинальные токены не терялись после стемминга. Например "кровати" будут преобразованы стеммером в "кровать". | |
Но мы хотим, чтобы и "кровати" тоже были в индексе, и при поиске "кровати" тоже нашлись, а не только "кровать". | |
Часто бывает нужно, чтобы совпадение в оригинальной форме приводило к более высокому score товара. --> | |
<filter class="solr.KeywordRepeatFilterFactory"/> | |
<filter class="solr.HunspellStemFilterFactory" dictionary="ru_RU.dic" affix="ru_RU.aff" ignoreCase="true" /> | |
<filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ru.txt" format="snowball" /> | |
<!-- Чтобы удалить совпадающие токены (которые появились после работы KeywordRepeatFilterFactory) --> | |
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/> | |
</analyzer> | |
<analyzer type="query"> | |
<tokenizer class="solr.StandardTokenizerFactory"/> | |
<filter class="ru.dz.RusEnKeyboardLayoutFilterFactory"/> | |
<filter class="solr.LowerCaseFilterFactory"/> | |
<filter class="solr.KeywordRepeatFilterFactory"/> | |
<!-- Дополнительно к HunspellStemFilterFactory используем RussianLightStemFilterFactory для того, чтобы | |
слова типа "айфона" (которых нет в словаре ru_RU.dic) стеммились к "айфон" --> | |
<filter class="solr.RussianLightStemFilterFactory"/> | |
<filter class="solr.HunspellStemFilterFactory" dictionary="ru_RU.dic" affix="ru_RU.aff" ignoreCase="true" /> | |
<filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ru.txt" format="snowball" /> | |
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/> | |
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="false"/> | |
</analyzer> | |
</fieldType> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment