├── settings.gradle ├── config ├── elasticsearch.yml └── logging.yml ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── plugin-descriptor.properties ├── LICENSE.md ├── src ├── main │ ├── java │ │ └── org │ │ │ ├── elasticsearch │ │ │ ├── index │ │ │ │ └── analysis │ │ │ │ │ └── ukrainian_lemmatizer │ │ │ │ │ ├── UkrainianLemmatizerCharFilterFactory.java │ │ │ │ │ ├── UkrainianLemmatizerTokenFilterFactory.java │ │ │ │ │ └── UkrainianAnalyzerProvider.java │ │ │ ├── plugin │ │ │ │ └── analysis │ │ │ │ │ └── ukrainian_lemmatizer │ │ │ │ │ └── UkrainianLemmatizerPlugin.java │ │ │ └── indices │ │ │ │ └── analysis │ │ │ │ └── ukrainian_lemmatizer │ │ │ │ └── UkrainianAnalyzer.java │ │ │ └── sotnya │ │ │ └── lemmatizer │ │ │ └── uk │ │ │ └── engine │ │ │ └── UkrainianLemmatizerResources.java │ └── resources │ │ └── stopwords.txt └── test │ ├── java │ └── org │ │ └── elasticsearch │ │ └── index │ │ └── analysis │ │ ├── TestAnalysisServiceProvider.java │ │ ├── TestUkrainianAnalysisIntegration.java │ │ └── TestUkrainianAnalyzer.java │ └── resources │ └── stopwords.txt ├── Dockerfile ├── test.sh ├── gradlew.bat ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'elasticsearch-ukrainian-lemmatizer' 2 | -------------------------------------------------------------------------------- /config/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | cluster.name: analyzer-test 2 | network.host: 127.0.0.1 3 | discovery.zen.ping.multicast.enabled: false 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | .settings/ 4 | bin/ 5 | build/ 6 | data/ 7 | 8 | .classpath 9 | .DS_Store 10 | .project 11 | *.iml -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrgambal/elasticsearch-ukrainian-lemmatizer/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Mar 22 09:39:35 EET 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /plugin-descriptor.properties: -------------------------------------------------------------------------------- 1 | name=ukrainian-lemmatizer 2 | description=ukrainian-lemmatizer - search across documents, written in ukrainian 3 | classname=org.elasticsearch.plugin.analysis.ukrainian_lemmatizer.UkrainianLemmatizerPlugin 4 | 5 | jvm=true 6 | site=false 7 | 8 | java.version=1.8 9 | 10 | version=${version} 11 | elasticsearch.version=${es_version} 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2018 Dmytro Hambal 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/index/analysis/ukrainian_lemmatizer/UkrainianLemmatizerCharFilterFactory.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.index.analysis.ukrainian_lemmatizer; 2 | 3 | import org.apache.lucene.analysis.charfilter.MappingCharFilter; 4 | import org.elasticsearch.common.settings.Settings; 5 | import org.elasticsearch.env.Environment; 6 | import org.elasticsearch.index.IndexSettings; 7 | import org.elasticsearch.index.analysis.AbstractCharFilterFactory; 8 | import org.sotnya.lemmatizer.uk.engine.UkrainianLemmatizerResources; 9 | 10 | import java.io.Reader; 11 | 12 | public class UkrainianLemmatizerCharFilterFactory extends AbstractCharFilterFactory { 13 | public UkrainianLemmatizerCharFilterFactory(IndexSettings indexSettings, 14 | Environment env, 15 | String name, 16 | Settings settings) { 17 | super(indexSettings, name); 18 | } 19 | 20 | @Override 21 | public Reader create(Reader tokenStream) { 22 | return new MappingCharFilter(UkrainianLemmatizerResources.NORMALIZE_MAP, tokenStream); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/logging.yml: -------------------------------------------------------------------------------- 1 | rootLogger: INFO, console, file 2 | logger: 3 | # log action execution errors for easier debugging 4 | action: DEBUG 5 | # reduce the logging for aws, too much is logged under the default INFO 6 | com.amazonaws: WARN 7 | 8 | # gateway 9 | #gateway: DEBUG 10 | #index.gateway: DEBUG 11 | 12 | # peer shard recovery 13 | #indices.recovery: DEBUG 14 | 15 | # discovery 16 | #discovery: TRACE 17 | 18 | index.search.slowlog: TRACE, index_search_slow_log_file 19 | 20 | additivity: 21 | index.search.slowlog: false 22 | 23 | appender: 24 | console: 25 | type: console 26 | layout: 27 | type: consolePattern 28 | conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" 29 | 30 | file: 31 | type: dailyRollingFile 32 | file: ${path.logs}/${cluster.name}.log 33 | datePattern: "'.'yyyy-MM-dd" 34 | layout: 35 | type: pattern 36 | conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" 37 | 38 | index_search_slow_log_file: 39 | type: dailyRollingFile 40 | file: ${path.logs}/${cluster.name}_index_search_slowlog.log 41 | datePattern: "'.'yyyy-MM-dd" 42 | layout: 43 | type: pattern 44 | conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n" 45 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/index/analysis/ukrainian_lemmatizer/UkrainianLemmatizerTokenFilterFactory.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.index.analysis.ukrainian_lemmatizer; 2 | 3 | import org.apache.lucene.analysis.TokenStream; 4 | import org.apache.lucene.analysis.morfologik.MorfologikFilter; 5 | import org.elasticsearch.common.settings.Settings; 6 | import org.elasticsearch.env.Environment; 7 | import org.elasticsearch.index.IndexSettings; 8 | import org.elasticsearch.index.analysis.AbstractTokenFilterFactory; 9 | import org.sotnya.lemmatizer.uk.engine.UkrainianLemmatizerResources; 10 | 11 | 12 | public final class UkrainianLemmatizerTokenFilterFactory extends AbstractTokenFilterFactory { 13 | public UkrainianLemmatizerTokenFilterFactory(IndexSettings indexSettings, 14 | Environment environment, 15 | String name, 16 | Settings settings) { 17 | super(indexSettings, name, settings); 18 | } 19 | 20 | @Override 21 | public String name() { 22 | return "ukrainian"; 23 | } 24 | 25 | @Override 26 | public TokenStream create(TokenStream tokenStream) { 27 | return new MorfologikFilter(tokenStream, UkrainianLemmatizerResources.getDictionary()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/elasticsearch/index/analysis/TestAnalysisServiceProvider.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.index.analysis; 2 | 3 | import org.apache.lucene.analysis.Analyzer; 4 | import org.elasticsearch.common.settings.Settings; 5 | import org.elasticsearch.index.Index; 6 | import org.elasticsearch.index.analysis.ukrainian_lemmatizer.UkrainianLemmatizerTokenFilterFactory; 7 | import org.elasticsearch.indices.analysis.ukrainian_lemmatizer.UkrainianAnalyzer; 8 | import org.elasticsearch.plugin.analysis.ukrainian_lemmatizer.UkrainianLemmatizerPlugin; 9 | import org.elasticsearch.test.ESTestCase; 10 | import org.hamcrest.MatcherAssert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | 14 | import java.io.IOException; 15 | 16 | import static org.hamcrest.Matchers.instanceOf; 17 | 18 | @RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) 19 | public class TestAnalysisServiceProvider extends ESTestCase { 20 | @Test 21 | public void testDefaultsUkrainianAnalysis() throws IOException { 22 | final TestAnalysis analysis = createTestAnalysis( 23 | new Index("test", "_na_"), 24 | Settings.EMPTY, 25 | new UkrainianLemmatizerPlugin()); 26 | 27 | TokenFilterFactory tokenizerFactory = analysis.tokenFilter.get("ukrainian"); 28 | 29 | MatcherAssert.assertThat(tokenizerFactory, instanceOf(UkrainianLemmatizerTokenFilterFactory.class)); 30 | 31 | Analyzer analyzer = analysis.indexAnalyzers.get("ukrainian").analyzer(); 32 | 33 | MatcherAssert.assertThat(analyzer, instanceOf(UkrainianAnalyzer.class)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # STAGE I: build the plugin. 2 | ARG ES_VERSION 3 | ARG PLUGIN_VERSION 4 | 5 | FROM java:8-jdk-alpine as builder 6 | 7 | ENV _JAVA_OPTIONS '-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+TieredCompilation -Xms256m -Xmx1536m -Xss1m' 8 | ENV BUILD_PATH '/app' 9 | 10 | RUN \ 11 | apk add --update \ 12 | bash \ 13 | ca-certificates \ 14 | && update-ca-certificates \ 15 | && rm -rf /var/cache/apk/* 16 | # Take everything we need into the container 17 | WORKDIR ${BUILD_PATH} 18 | COPY config ${BUILD_PATH}/config 19 | COPY gradle ${BUILD_PATH}/gradle 20 | COPY src ${BUILD_PATH}/src 21 | COPY gradlew ${BUILD_PATH} 22 | COPY build.gradle ${BUILD_PATH} 23 | COPY settings.gradle ${BUILD_PATH} 24 | COPY plugin-descriptor.properties ${BUILD_PATH} 25 | # ES won't run under root 26 | RUN adduser -D -u 1000 builder 27 | RUN chown -R builder:users ${BUILD_PATH} 28 | USER builder 29 | # Test and build the artifact. 30 | ENV GRADLE_USER_HOME=/tmp/.gradle 31 | RUN ./gradlew clean cleanTest test release 32 | 33 | # STAGE II: build the image of ES with plugin inluded. 34 | # Let's continue with a fresh ES installation. 35 | # Port 9200 is exposed by default. 36 | FROM elasticsearch:${ES_VERSION}-alpine 37 | ARG PLUGIN_VERSION 38 | # Do not forget about the artifact we produced 39 | COPY --from=builder /app/build/distributions/elasticsearch-ukrainian-lemmatizer-${PLUGIN_VERSION}.zip /tmp 40 | 41 | ENV ES_HOME '/usr/share/elasticsearch' 42 | RUN chown -R elasticsearch ${ES_HOME} 43 | 44 | USER elasticsearch 45 | 46 | WORKDIR ${ES_HOME} 47 | 48 | RUN ./bin/plugin install file:/tmp/elasticsearch-ukrainian-lemmatizer-${PLUGIN_VERSION}.zip 49 | 50 | CMD ["./bin/elasticsearch"] 51 | 52 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/index/analysis/ukrainian_lemmatizer/UkrainianAnalyzerProvider.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.index.analysis.ukrainian_lemmatizer; 2 | 3 | import org.apache.lucene.analysis.CharArraySet; 4 | import org.elasticsearch.common.settings.Settings; 5 | import org.elasticsearch.env.Environment; 6 | import org.elasticsearch.index.IndexSettings; 7 | import org.elasticsearch.index.analysis.AbstractIndexAnalyzerProvider; 8 | import org.elasticsearch.index.analysis.Analysis; 9 | import org.elasticsearch.indices.analysis.ukrainian_lemmatizer.UkrainianAnalyzer; 10 | import org.sotnya.lemmatizer.uk.engine.UkrainianLemmatizerResources; 11 | 12 | public final class UkrainianAnalyzerProvider extends AbstractIndexAnalyzerProvider { 13 | 14 | private final UkrainianAnalyzer analyzer; 15 | 16 | public UkrainianAnalyzerProvider(IndexSettings indexSettings, 17 | Environment env, 18 | String name, 19 | Settings settings) { 20 | super(indexSettings, name, settings); 21 | 22 | analyzer = new UkrainianAnalyzer( 23 | new UkrainianLemmatizerTokenFilterFactory(indexSettings, env, name, settings), 24 | new UkrainianLemmatizerCharFilterFactory(indexSettings, env, name, settings), 25 | Analysis.parseStopWords(env, settings, UkrainianLemmatizerResources.getDefaultStopSet()), 26 | Analysis.parseStemExclusion(settings, CharArraySet.EMPTY_SET) 27 | ); 28 | } 29 | 30 | @Override 31 | public UkrainianAnalyzer get() { 32 | return this.analyzer; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/plugin/analysis/ukrainian_lemmatizer/UkrainianLemmatizerPlugin.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.plugin.analysis.ukrainian_lemmatizer; 2 | 3 | import org.apache.lucene.analysis.Analyzer; 4 | import org.elasticsearch.index.analysis.AnalyzerProvider; 5 | import org.elasticsearch.index.analysis.CharFilterFactory; 6 | import org.elasticsearch.index.analysis.TokenFilterFactory; 7 | import org.elasticsearch.index.analysis.ukrainian_lemmatizer.UkrainianAnalyzerProvider; 8 | import org.elasticsearch.index.analysis.ukrainian_lemmatizer.UkrainianLemmatizerCharFilterFactory; 9 | import org.elasticsearch.index.analysis.ukrainian_lemmatizer.UkrainianLemmatizerTokenFilterFactory; 10 | import org.elasticsearch.indices.analysis.AnalysisModule; 11 | import org.elasticsearch.plugins.AnalysisPlugin; 12 | import org.elasticsearch.plugins.Plugin; 13 | 14 | import java.util.Collections; 15 | import java.util.Map; 16 | 17 | public final class UkrainianLemmatizerPlugin extends Plugin implements AnalysisPlugin { 18 | 19 | @Override 20 | public Map> getCharFilters() { 21 | return Collections.singletonMap("ukrainian", UkrainianLemmatizerCharFilterFactory::new); 22 | } 23 | 24 | @Override 25 | public Map> getTokenFilters() { 26 | return Collections.singletonMap("ukrainian", UkrainianLemmatizerTokenFilterFactory::new); 27 | } 28 | 29 | @Override 30 | public Map>> getAnalyzers() { 31 | return Collections.singletonMap("ukrainian", UkrainianAnalyzerProvider::new); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Remove old data 3 | curl -XDELETE "http://localhost:9200/ukrainian" 4 | 5 | # Create index with settings. Add "гусята" to the stopwords list. 6 | curl -XPUT "http://localhost:9200/ukrainian/" -H 'Content-Type: application/json' -d ' 7 | { 8 | "settings": { 9 | "analysis": { 10 | "analyzer": { 11 | "my_ukrainian": { 12 | "type": "ukrainian", 13 | "stopwords": [ 14 | "гусята" 15 | ] 16 | } 17 | } 18 | } 19 | } 20 | } 21 | ' 22 | 23 | # Define mapping 24 | curl -XPOST "http://localhost:9200/ukrainian/user/_mapping" -H 'Content-Type: application/json' -d ' 25 | { 26 | "user":{ 27 | "properties":{ 28 | "test":{ 29 | "type":"string", 30 | "analyzer":"my_ukrainian" 31 | } 32 | } 33 | } 34 | } 35 | ' 36 | 37 | # Create documents 38 | curl -XPOST "http://localhost:9200/ukrainian/user/_bulk" -H 'Content-Type: application/json' -d ' 39 | {"create": {"_id": 1}} 40 | { "test": "гусята" } 41 | {"create": {"_id": 2}} 42 | { "test": "гусяти" } 43 | {"create": {"_id": 3}} 44 | { "test": "гусятам" } 45 | {"create": {"_id": 4}} 46 | { "test": "підострожує" } 47 | {"create": {"_id": 5}} 48 | { "test": "п’яничка" } 49 | ' 50 | 51 | # Wait for ES to be synced (aka refresh indices) 52 | curl -XPOST "http://localhost:9200/ukrainian/_refresh" 53 | 54 | # Search with the word "гусята" being blacklisted. 55 | curl -XPOST "http://localhost:9200/ukrainian/user/_search?pretty=true" -H 'Content-Type: application/json' -d ' 56 | { 57 | "query":{ 58 | "match":{ 59 | "test": { 60 | "query": "гусятах", 61 | "analyzer": "my_ukrainian" 62 | } 63 | } 64 | } 65 | } 66 | ' 67 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/test/java/org/elasticsearch/index/analysis/TestUkrainianAnalysisIntegration.java: -------------------------------------------------------------------------------- 1 | package org.elasticsearch.index.analysis; 2 | 3 | import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse; 4 | import org.elasticsearch.common.xcontent.XContentBuilder; 5 | import org.elasticsearch.plugin.analysis.ukrainian_lemmatizer.UkrainianLemmatizerPlugin; 6 | import org.elasticsearch.plugins.Plugin; 7 | import org.elasticsearch.test.ESIntegTestCase; 8 | import org.hamcrest.MatcherAssert; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | import java.util.Collection; 13 | import java.util.Collections; 14 | import java.util.concurrent.ExecutionException; 15 | 16 | import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 17 | import static org.hamcrest.Matchers.is; 18 | import static org.hamcrest.Matchers.notNullValue; 19 | 20 | @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, numDataNodes = 1) 21 | public class TestUkrainianAnalysisIntegration extends ESIntegTestCase { 22 | 23 | @Override 24 | protected Collection> nodePlugins() { 25 | return Collections.singleton(UkrainianLemmatizerPlugin.class); 26 | } 27 | 28 | @Test 29 | public void testUkrainianAnalyzer() throws ExecutionException, InterruptedException { 30 | AnalyzeResponse response = client().admin().indices() 31 | .prepareAnalyze("б'ючи іменинника").setAnalyzer("ukrainian") 32 | .execute().get(); 33 | 34 | MatcherAssert.assertThat(response, notNullValue()); 35 | MatcherAssert.assertThat(response.getTokens().size(), is(2)); 36 | } 37 | 38 | @Test 39 | public void testUkrainianLemmatizerTokenFilter() throws ExecutionException, InterruptedException { 40 | AnalyzeResponse response = client().admin().indices() 41 | .prepareAnalyze("конденсаторної").addTokenFilter("ukrainian") 42 | .execute().get(); 43 | 44 | MatcherAssert.assertThat(response, notNullValue()); 45 | MatcherAssert.assertThat(response.getTokens().size(), is(1)); 46 | } 47 | 48 | @Test 49 | public void testUkrainianAnalyzerInMapping() throws IOException { 50 | final XContentBuilder mapping = jsonBuilder().startObject() 51 | .startObject("type") 52 | .startObject("properties") 53 | .startObject("foo") 54 | .field("type", "string") 55 | .field("analyzer", "ukrainian") 56 | .endObject() 57 | .endObject() 58 | .endObject() 59 | .endObject(); 60 | 61 | client().admin().indices().prepareCreate("test").addMapping("type", mapping).get(); 62 | 63 | index("test", "type", "1", "foo", "б'ючи іменинника"); 64 | 65 | ensureYellow(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/sotnya/lemmatizer/uk/engine/UkrainianLemmatizerResources.java: -------------------------------------------------------------------------------- 1 | package org.sotnya.lemmatizer.uk.engine; 2 | 3 | import morfologik.stemming.Dictionary; 4 | import org.apache.logging.log4j.Logger; 5 | import org.apache.lucene.analysis.CharArraySet; 6 | import org.apache.lucene.analysis.WordlistLoader; 7 | import org.apache.lucene.analysis.charfilter.NormalizeCharMap; 8 | import org.apache.lucene.util.IOUtils; 9 | import org.elasticsearch.common.logging.ESLoggerFactory; 10 | 11 | import java.io.IOException; 12 | import java.io.Reader; 13 | import java.nio.charset.StandardCharsets; 14 | 15 | /** 16 | * Serves purposes of safe loading of static resources and providing them to other parts of the application. 17 | */ 18 | public final class UkrainianLemmatizerResources { 19 | /** 20 | * File containing default Ukrainian stopwords. 21 | */ 22 | private static final String DEFAULT_STOPWORD_FILE = "stopwords.txt"; 23 | /** 24 | * Path to the file that contains the actual mapping. 25 | * The file stored within the `morfologik-ukrainian-search` package. 26 | */ 27 | private static final String DICTIONARY_FILE_PATH = "ua/net/nlp/ukrainian.dict"; 28 | 29 | private static final Logger LOGGER = ESLoggerFactory.getLogger(UkrainianLemmatizerResources.class.getSimpleName()); 30 | 31 | public static final NormalizeCharMap NORMALIZE_MAP = new NormalizeCharMap.Builder() {{ 32 | // different apostrophes 33 | add("\u2019", "'"); 34 | add("\u2018", "'"); 35 | add("\u02BC", "'"); 36 | add("`", "'"); 37 | add("´", "'"); 38 | // ignored characters 39 | add("\u0301", ""); 40 | add("\u00AD", ""); 41 | add("ґ", "г"); 42 | add("Ґ", "Г"); 43 | }}.build(); 44 | 45 | /** 46 | * Returns an unmodifiable instance of the default stop words set. 47 | * 48 | * @return default stop words set. 49 | */ 50 | public static CharArraySet getDefaultStopSet() { 51 | return DefaultsHolder.DEFAULT_STOP_SET; 52 | } 53 | 54 | /** 55 | * Reads a .dict file produced by morfologik-ukrainian-search and constructs a new dictionary from it. 56 | * In case of file's absence must fail with {@link IOException}. 57 | * 58 | * @return New instance of morfologik {@link Dictionary} to be used in token filters. 59 | */ 60 | public static Dictionary getDictionary() { 61 | return DefaultsHolder.DEFAULT_DICTIONARY; 62 | } 63 | 64 | /** 65 | * Atomically loads the DEFAULT_STOP_SET and DEFAULT_DICTIONARY in a lazy fashion once the outer class 66 | * accesses the static final set the first time.; 67 | */ 68 | private static class DefaultsHolder { 69 | static final CharArraySet DEFAULT_STOP_SET; 70 | static final Dictionary DEFAULT_DICTIONARY; 71 | 72 | static { 73 | final ClassLoader loader = DefaultsHolder.class.getClassLoader(); 74 | 75 | try { 76 | final Reader decodingReader = IOUtils.getDecodingReader( 77 | loader.getResourceAsStream(DEFAULT_STOPWORD_FILE), 78 | StandardCharsets.UTF_8); 79 | 80 | DEFAULT_STOP_SET = WordlistLoader.getSnowballWordSet(decodingReader); 81 | 82 | if (LOGGER.isDebugEnabled()) 83 | LOGGER.debug("The stop-set has been loaded."); 84 | } catch (IOException | NullPointerException ex) { 85 | // default set should always be present as it is part of the 86 | // distribution (JAR) 87 | throw new RuntimeException("Unable to load default stopword set"); 88 | } 89 | 90 | if (LOGGER.isDebugEnabled()) 91 | LOGGER.debug("Started loading the ukrainian dictionary."); 92 | 93 | try { 94 | DEFAULT_DICTIONARY = Dictionary.read(loader.getResource(DICTIONARY_FILE_PATH)); 95 | 96 | if (LOGGER.isDebugEnabled()) 97 | LOGGER.debug("The ukrainian dictionary has been loaded successfully."); 98 | } catch (IOException | NullPointerException ex) { 99 | throw new RuntimeException(ex); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/org/elasticsearch/index/analysis/TestUkrainianAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.elasticsearch.index.analysis; 18 | 19 | import org.apache.lucene.analysis.Analyzer; 20 | import org.apache.lucene.analysis.BaseTokenStreamTestCase; 21 | import org.elasticsearch.Version; 22 | import org.elasticsearch.cluster.metadata.IndexMetaData; 23 | import org.elasticsearch.common.settings.Settings; 24 | import org.elasticsearch.env.Environment; 25 | import org.elasticsearch.index.Index; 26 | import org.elasticsearch.index.IndexSettings; 27 | import org.elasticsearch.index.analysis.ukrainian_lemmatizer.UkrainianAnalyzerProvider; 28 | import org.elasticsearch.indices.analysis.ukrainian_lemmatizer.UkrainianAnalyzer; 29 | import org.elasticsearch.test.IndexSettingsModule; 30 | 31 | import java.io.IOException; 32 | 33 | /** 34 | * Test case for UkrainianAnalyzer. 35 | */ 36 | public class TestUkrainianAnalyzer extends BaseTokenStreamTestCase { 37 | private final Index index = new Index("test", "_na_"); 38 | private final Settings ixSettings = Settings 39 | .builder() 40 | .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()) 41 | .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) 42 | .build(); 43 | private final IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(index, ixSettings); 44 | private final Environment env = new Environment(ixSettings); 45 | 46 | 47 | private UkrainianAnalyzer getUkrainianAnalyzer() { 48 | return new UkrainianAnalyzerProvider(indexSettings, env, index.getName(), Settings.EMPTY).get(); 49 | } 50 | 51 | /** 52 | * Check that UkrainianAnalyzer doesn't discard any numbers 53 | */ 54 | public void testDigitsInUkrainianCharset() throws IOException { 55 | UkrainianAnalyzer ua = getUkrainianAnalyzer(); 56 | assertAnalyzesTo(ua, "text 1000", new String[]{"text", "1000"}); 57 | ua.close(); 58 | } 59 | 60 | public void testReusableTokenStream() throws Exception { 61 | Analyzer ua = getUkrainianAnalyzer(); 62 | assertAnalyzesTo(ua, 63 | "Ця п'єса, у свою чергу, рухається по емоційно-напруженому колу за ритм-енд-блюзом.", 64 | new String[]{"п'єса", "черга", "рухатися", "емоційно", "напружений", "кола", "коло", "кіл", "ритм", "енд", "блюз"}); 65 | ua.close(); 66 | } 67 | 68 | public void testSpecialCharsTokenStream() throws Exception { 69 | Analyzer a = getUkrainianAnalyzer(); 70 | assertAnalyzesTo(a, 71 | "м'яса м'я\u0301са м\u02BCяса м\u2019яса м\u2018яса м`яса", 72 | new String[]{"м'ясо", "м'ясо", "м'ясо", "м'ясо", "м'ясо", "м'ясо"}); 73 | a.close(); 74 | } 75 | 76 | public void testCapsTokenStream() throws Exception { 77 | Analyzer a = getUkrainianAnalyzer(); 78 | assertAnalyzesTo(a, "Цих Чайковського і Ґете.", 79 | new String[]{"Чайковське", "Чайковський", "Гете"}); 80 | a.close(); 81 | } 82 | 83 | public void testSampleSentence() throws Exception { 84 | Analyzer a = getUkrainianAnalyzer(); 85 | assertAnalyzesTo(a, "Це — проект генерування словника з тегами частин мови для української мови.", 86 | new String[]{"проект", "генерування", "словник", "тег", "частина", "мова", "українська", "український", "Українська", "мова"}); 87 | a.close(); 88 | } 89 | 90 | /** 91 | * blast some random strings through the analyzer 92 | */ 93 | public void testRandomStrings() throws Exception { 94 | Analyzer analyzer = getUkrainianAnalyzer(); 95 | checkRandomData(random(), analyzer, 1000 * RANDOM_MULTIPLIER); 96 | analyzer.close(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/elasticsearch/indices/analysis/ukrainian_lemmatizer/UkrainianAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.elasticsearch.indices.analysis.ukrainian_lemmatizer; 18 | 19 | import org.apache.lucene.analysis.Analyzer; 20 | import org.apache.lucene.analysis.CharArraySet; 21 | import org.apache.lucene.analysis.StopwordAnalyzerBase; 22 | import org.apache.lucene.analysis.TokenStream; 23 | import org.apache.lucene.analysis.Tokenizer; 24 | import org.apache.lucene.analysis.core.LowerCaseFilter; 25 | import org.apache.lucene.analysis.core.StopFilter; 26 | import org.apache.lucene.analysis.miscellaneous.SetKeywordMarkerFilter; 27 | import org.apache.lucene.analysis.morfologik.MorfologikFilter; 28 | import org.apache.lucene.analysis.standard.StandardFilter; 29 | import org.apache.lucene.analysis.standard.StandardTokenizer; 30 | import org.elasticsearch.index.analysis.CharFilterFactory; 31 | import org.elasticsearch.index.analysis.TokenFilterFactory; 32 | import org.sotnya.lemmatizer.uk.engine.UkrainianLemmatizerResources; 33 | 34 | import java.io.Reader; 35 | 36 | /** 37 | * A back-ported version of dictionary-based {@link Analyzer} for Ukrainian. 38 | * Original file is located here https://github.com/apache/lucene-solr/blob/master/lucene/analysis/morfologik/src/java/org/apache/lucene/analysis/uk/UkrainianMorfologikAnalyzer.java . 39 | */ 40 | public final class UkrainianAnalyzer extends StopwordAnalyzerBase { 41 | private final CharArraySet stemExclusionSet; 42 | private final CharFilterFactory charFilterFactory; 43 | private final TokenFilterFactory tokenFilterFactory; 44 | 45 | /** 46 | * Builds an analyzer with the default stop words. 47 | * 48 | * @param tokenFilterFactory A provider for the corresponding token filter. 49 | * @param charFilterFactory A provider for the corresponding character filter. 50 | */ 51 | public UkrainianAnalyzer( 52 | TokenFilterFactory tokenFilterFactory, 53 | CharFilterFactory charFilterFactory 54 | ) { 55 | this(tokenFilterFactory, charFilterFactory, UkrainianLemmatizerResources.getDefaultStopSet()); 56 | } 57 | 58 | /** 59 | * Builds an analyzer with the given stop words. 60 | * 61 | * @param tokenFilterFactory A provider for the corresponding token filter. 62 | * @param charFilterFactory A provider for the corresponding character filter. 63 | * @param stopwords a stopword set 64 | */ 65 | public UkrainianAnalyzer( 66 | TokenFilterFactory tokenFilterFactory, 67 | CharFilterFactory charFilterFactory, 68 | CharArraySet stopwords 69 | ) { 70 | this(tokenFilterFactory, charFilterFactory, stopwords, CharArraySet.EMPTY_SET); 71 | } 72 | 73 | /** 74 | * Builds an analyzer with the given stop words. If a non-empty stem exclusion set is 75 | * provided this analyzer will add a {@link SetKeywordMarkerFilter} before 76 | * stemming. 77 | * 78 | * @param tokenFilterFactory A provider for the corresponding token filter. 79 | * @param charFilterFactory A provider for the corresponding character filter. 80 | * @param stopwords a stopword set 81 | * @param stemExclusionSet a set of terms not to be stemmed 82 | */ 83 | public UkrainianAnalyzer( 84 | TokenFilterFactory tokenFilterFactory, 85 | CharFilterFactory charFilterFactory, 86 | CharArraySet stopwords, 87 | CharArraySet stemExclusionSet 88 | ) { 89 | super(stopwords); 90 | 91 | this.stemExclusionSet = CharArraySet.unmodifiableSet(CharArraySet.copy(stemExclusionSet)); 92 | this.charFilterFactory = charFilterFactory; 93 | this.tokenFilterFactory = tokenFilterFactory; 94 | } 95 | 96 | @Override 97 | protected Reader initReader(String fieldName, Reader reader) { 98 | return charFilterFactory.create(reader); 99 | } 100 | 101 | /** 102 | * Creates a {@link TokenStreamComponents} 103 | * which tokenizes all the text in the provided {@link Reader}. 104 | * 105 | * @return A {@link TokenStreamComponents} 106 | * built from an {@link StandardTokenizer} filtered with 107 | * {@link StandardFilter}, {@link LowerCaseFilter}, {@link StopFilter} 108 | * , {@link SetKeywordMarkerFilter} if a stem exclusion set is 109 | * provided and {@link MorfologikFilter} on the Ukrainian dictionary. 110 | */ 111 | @Override 112 | protected TokenStreamComponents createComponents(String fieldName) { 113 | Tokenizer source = new StandardTokenizer(); 114 | TokenStream result = new StandardFilter(source); 115 | 116 | result = new LowerCaseFilter(result); 117 | result = new StopFilter(result, stopwords); 118 | 119 | if (!stemExclusionSet.isEmpty()) { 120 | result = new SetKeywordMarkerFilter(result, stemExclusionSet); 121 | } 122 | 123 | result = tokenFilterFactory.create(result); 124 | 125 | return new TokenStreamComponents(source, result); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ukrainian lemmatizer plugin for ElasticSearch [1.7 - 5.x] 2 | 3 | The plugin provides an ability for ElasticSearch installations prior to version 6 (to be expanded) to search across documents, written in ukrainian, using words in different forms. 4 | Starting from version 5.0 ElasticSearch uses [Lucene][Lucene] of version 6.2, which provides support for ukrainian language analysis [out of the box](https://issues.apache.org/jira/browse/LUCENE-7287). 5 | However, this plugin is still worthy, I swear! It uses the latest and greatest from [the BrUk project][BrUk], and, moreover, it allows specifying arbitrary stop-words. 6 | 7 | ## Principles 8 | 9 | The thing is, it makes you able to index not source words but their lemmas (lemma – canonical form of a word), and also perform a lookup using different forms of the same word which will return you what you're looking for. Needless to say, the magic is being done under the hood! No more doubts like: "What if I put this word in plural? Maybe it'll finally find something?". 10 | Each term before settling in the storage passes through the analyzer to check if there is a lemma for the term and, in case of success, this lemma must get into index. The same sequence of actions has the place when you start a lookup over documents stored using the analyzer: it converts your search terms according to dictionary and return results if there is any match. 11 | As the source of lemmas the plugin uses the dictionary from [the BrUk project][BrUk]. 12 | 13 | ## Get plugin 14 | 15 | **Note**: I won't release a build for ES 2.2.0 due to an ugly [bug][permissions]. 16 | 17 | You always can get latest ready-to-go builds on the [Releases page][releases]. 18 | Download a zip-file with the corresponding version of ES supported and install it with: 19 | 20 | ### ES 1.7.+ 21 | ```/plugin --url file:///elasticsearch-ukrainian-lemmatizer-1.0-SNAPSHOT.zip --install ukrainian-lemmatizer``` 22 | 23 | ### ES 2.0.0-2.4.6 24 | ```/plugin install file:/elasticsearch-ukrainian-lemmatizer-.zip``` 25 | 26 | ### For ES version 5+ 27 | ```/elasticsearch-plugin install file:/elasticsearch-ukrainian-lemmatizer-.zip``` 28 | 29 | ## Build the plugin 30 | 31 | Manual building of the plugin consists of only 4 steps: 32 | 33 | * Clone this repository 34 | * Get inside the root dir of the cloned repo and run ```gradle release``` 35 | * Find the built artifact in ```build/distributions/```. 36 | 37 | ## Usage 38 | 39 | Here are simple example of the plugin usage that rely on ES HTTP API. 40 | First we need to create the index which must include our analyzer. But let's make it in a way a bit fancier than the usual one: make it a part of a custom analyzer with an additional list of stopwords. In effect, only the word "гусята" is to be blacklisted. 41 | 42 | ```shell 43 | # Create index with settings 44 | curl -XPUT "http://localhost:9200/ukrainian/" -H 'Content-Type: application/json' -d ' 45 | { 46 | "settings": { 47 | "analysis": { 48 | "analyzer": { 49 | "my_ukrainian": { 50 | "type": "ukrainian", 51 | "stopwords": [ 52 | "гусята" 53 | ] 54 | } 55 | } 56 | } 57 | } 58 | } 59 | ' 60 | ``` 61 | 62 | Then we create a simple mapping: 63 | 64 | ```shell 65 | # Define mapping 66 | curl -XPOST "http://localhost:9200/ukrainian/user/_mapping" -H 'Content-Type: application/json' -d ' 67 | { 68 | "user":{ 69 | "properties":{ 70 | "test":{ 71 | "type":"string", 72 | "analyzer":"my_ukrainian" 73 | } 74 | } 75 | } 76 | } 77 | ' 78 | ``` 79 | 80 | And fill the index with a sample data: 81 | 82 | ```shell 83 | # Create Documents 84 | curl -XPOST "http://localhost:9200/ukrainian/user/_bulk" -H 'Content-Type: application/json' -d ' 85 | {"create": {"_id": 1}} 86 | { "test": "гусята" } 87 | {"create": {"_id": 2}} 88 | { "test": "гусяти" } 89 | {"create": {"_id": 3}} 90 | { "test": "гусятам" } 91 | {"create": {"_id": 4}} 92 | { "test": "підострожує" } 93 | {"create": {"_id": 5}} 94 | { "test": "п’яничка" } 95 | ' 96 | ``` 97 | 98 | Having that done and filled this index with some data we can query it using the same analyzer: 99 | 100 | ```shell 101 | # Search 102 | curl -XPOST "http://localhost:9200/ukrainian/user/_search?pretty=true" -H 'Content-Type: application/json' -d ' 103 | { 104 | "query":{ 105 | "match":{ 106 | "test": { 107 | "query": "гусятах", 108 | "analyzer": "my_ukrainian" 109 | } 110 | } 111 | } 112 | } 113 | ' 114 | ``` 115 | 116 | And here is what you'll receive: 117 | 118 | ```json 119 | { 120 | "took": 104, 121 | "timed_out": false, 122 | "_shards": { 123 | "total": 5, 124 | "successful": 5, 125 | "failed": 0 126 | }, 127 | "hits": { 128 | "total": 2, 129 | "max_score": 0.5945348, 130 | "hits": [{ 131 | "_index": "ukrainian", 132 | "_type": "user", 133 | "_id": "AWE8Vt4G8T79yKC4TtYm", 134 | "_score": 0.5945348, 135 | "_source": { 136 | "test": "гусятам" 137 | } 138 | }, { 139 | "_index": "ukrainian", 140 | "_type": "user", 141 | "_id": "AWE8Vt4G8T79yKC4TtYo", 142 | "_score": 0.5945348, 143 | "_source": { 144 | "test": "гусяти" 145 | } 146 | }] 147 | } 148 | } 149 | ``` 150 | 151 | **Notice** you may find this particular example in ```test.sh``` inside the repository: you may use it for testing of serviceability of the plugin after you install it. 152 | 153 | ## Requirements 154 | 155 | * ES 156 | - 1.7.+ (release v1.0) 157 | - 2.0.0 (release v1.1.0) 158 | - 2.0.1 (release v1.1.1) 159 | - 2.0.2 (release v1.1.3) 160 | - 2.1.0 (release v1.2.0) 161 | - 2.1.1 (release v1.2.1) 162 | - 2.1.2 (release v1.2.2) 163 | - 2.2.1 (release v1.3.0) 164 | - 2.3.3 (release v1.4.1) 165 | - 2.3.5 (release v1.4.3) 166 | - 2.4.6 (release v1.5.3) 167 | - 5.6.16 (release v1.6.0) 168 | * Java 8 169 | * Gradle 6+ 170 | 171 | [Lucene]: https://github.com/apache/lucene-solr/tree/master/lucene 172 | [BrUk]: https://github.com/brown-uk/corpus 173 | [releases]: https://github.com/mrgambal/elasticsearch-ukrainian-lemmatizer/releases "Plugin releases" 174 | [permissions]: https://github.com/elastic/elasticsearch/issues/16459 "Control access issue" 175 | -------------------------------------------------------------------------------- /src/main/resources/stopwords.txt: -------------------------------------------------------------------------------- 1 | а 2 | аби 3 | абиде 4 | абиколи 5 | абикуди 6 | абихто 7 | абикого 8 | абикому 9 | абиким 10 | абичий 11 | абичийого 12 | абичиєму 13 | абичийому 14 | абичиїм 15 | абичия 16 | абичиєї 17 | абичиїй 18 | абичию 19 | абичиєю 20 | абичиє 21 | абичиї 22 | абичиїх 23 | абичиїми 24 | абищо 25 | абичого 26 | абичому 27 | абичим 28 | абиякий 29 | абиякого 30 | абиякому 31 | абияким 32 | абиякім 33 | абияка 34 | абиякої 35 | абиякій 36 | абияку 37 | абиякою 38 | абияке 39 | абиякі 40 | абияких 41 | абиякими 42 | або 43 | абощо 44 | авжеж 45 | авось 46 | ага 47 | адже 48 | аж 49 | ажень 50 | але 51 | амінь 52 | ані 53 | аніде 54 | аніж 55 | анізащо 56 | анікогісінько 57 | аніколи 58 | аніскільки 59 | аніхто 60 | анікого 61 | анікому 62 | аніким 63 | анічогісінько 64 | аніщо 65 | анічого 66 | анічому 67 | анічим 68 | аніякий 69 | аніякого 70 | аніякому 71 | аніяким 72 | аніякім 73 | аніяка 74 | аніякої 75 | аніякій 76 | аніяку 77 | аніякою 78 | аніяке 79 | аніякі 80 | аніяких 81 | аніякими 82 | аніякісенький 83 | аніякісенького 84 | аніякісенькому 85 | аніякісеньким 86 | аніякісенькім 87 | аніякісенька 88 | аніякісенької 89 | аніякісенькій 90 | аніякісеньку 91 | аніякісенькою 92 | аніякісеньке 93 | аніякісенькі 94 | аніякісеньких 95 | аніякісенькими 96 | аніякісінький 97 | аніякісінького 98 | аніякісінькому 99 | аніякісіньким 100 | аніякісінькім 101 | аніякісінька 102 | аніякісінької 103 | аніякісінькій 104 | аніякісіньку 105 | аніякісінькою 106 | аніякісіньке 107 | аніякісінькі 108 | аніякісіньких 109 | аніякісінькими 110 | ану 111 | ато 112 | атож 113 | ач 114 | ачей 115 | аякже 116 | б 117 | ба 118 | багато 119 | багатьох 120 | багатьом 121 | багатьма 122 | без 123 | би 124 | біля 125 | бо 126 | бодай 127 | бути 128 | будь 129 | будьмо 130 | будьте 131 | є 132 | єси 133 | суть 134 | буду 135 | будеш 136 | буде 137 | будем 138 | будемо 139 | будете 140 | будуть 141 | був 142 | була 143 | було 144 | були 145 | буцім 146 | буцімто 147 | в 148 | ваш 149 | вашого 150 | вашому 151 | вашим 152 | вашім 153 | ваша 154 | вашої 155 | вашій 156 | вашу 157 | вашою 158 | ваше 159 | ваші 160 | ваших 161 | вашими 162 | ввесь 163 | всього 164 | всьому 165 | всім 166 | вся 167 | всієї 168 | всій 169 | всю 170 | всією 171 | все 172 | всі 173 | всіх 174 | всіма 175 | вві 176 | весь 177 | вздовж 178 | ви 179 | вас 180 | вам 181 | вами 182 | ві 183 | від 184 | відколи 185 | відповідно 186 | відтепер 187 | відтоді 188 | він 189 | його 190 | нього 191 | йому 192 | ним 193 | нім 194 | ньому 195 | власне 196 | властиво 197 | внаслідок 198 | вона 199 | її 200 | неї 201 | їй 202 | нею 203 | ній 204 | вони 205 | їх 206 | них 207 | їм 208 | ними 209 | воно 210 | вподовж 211 | впоперек 212 | впродовж 213 | всілякий 214 | всілякого 215 | всілякому 216 | всіляким 217 | всілякім 218 | всіляка 219 | всілякої 220 | всілякій 221 | всіляку 222 | всілякою 223 | всіляке 224 | всілякі 225 | всіляких 226 | всілякими 227 | вслід 228 | всупереч 229 | всюди 230 | всякий 231 | всякого 232 | всякому 233 | всяким 234 | всякім 235 | всяка 236 | всякої 237 | всякій 238 | всяку 239 | всякою 240 | всяке 241 | всякі 242 | всяких 243 | всякими 244 | всяк 245 | втім 246 | гаразд 247 | ге 248 | геть 249 | де 250 | дедалі 251 | деінде 252 | декілька 253 | декількох 254 | декільком 255 | декількома 256 | деколи 257 | декотрий 258 | декотрого 259 | декотрому 260 | декотрим 261 | декотрім 262 | декотра 263 | декотрої 264 | декотрій 265 | декотру 266 | декотрою 267 | декотре 268 | декотрі 269 | декотрих 270 | декотрими 271 | десь 272 | дехто 273 | декого 274 | декому 275 | деким 276 | декім 277 | дечий 278 | дечийого 279 | дечиєму 280 | дечийому 281 | дечиїм 282 | дечия 283 | дечиєї 284 | дечиїй 285 | дечию 286 | дечиєю 287 | дечиє 288 | дечиї 289 | дечиїх 290 | дечиїми 291 | дещо 292 | дечого 293 | дечому 294 | дечим 295 | дечім 296 | деякий 297 | деякого 298 | деякому 299 | деяким 300 | деякім 301 | деяка 302 | деякої 303 | деякій 304 | деяку 305 | деякою 306 | деяке 307 | деякі 308 | деяких 309 | деякими 310 | для 311 | до 312 | довкола 313 | доки 314 | допіру 315 | допоки 316 | досі 317 | дотепер 318 | доти 319 | еге 320 | ж 321 | же 322 | жодний 323 | жодного 324 | жодному 325 | жодним 326 | жоднім 327 | жодна 328 | жодної 329 | жодній 330 | жодну 331 | жодною 332 | жодне 333 | жодні 334 | жодних 335 | жодними 336 | жоден 337 | жоднісінький 338 | жоднісінького 339 | жоднісінькому 340 | жоднісіньким 341 | жоднісінькім 342 | жоднісінька 343 | жоднісінької 344 | жоднісінькій 345 | жоднісіньку 346 | жоднісінькою 347 | жоднісіньке 348 | жоднісінькі 349 | жоднісіньких 350 | жоднісінькими 351 | з 352 | за 353 | завгодно 354 | завдяки 355 | завжди 356 | завше 357 | задля 358 | залежно 359 | замість 360 | заради 361 | зараз 362 | зате 363 | зверху 364 | звідки 365 | звідкилясь 366 | звідкись 367 | звідкіль 368 | звідкіля 369 | звідкілясь 370 | звідси 371 | звідсіль 372 | звідсіля 373 | звідти 374 | звідтіль 375 | звідтіля 376 | звідусіль 377 | звідусюди 378 | звідціля 379 | здовж 380 | ззаду 381 | зі 382 | зо 383 | зсередини 384 | ич 385 | і 386 | ібн 387 | із 388 | ізсередини 389 | інакше 390 | інакший 391 | інакшого 392 | інакшому 393 | інакшим 394 | інакшім 395 | інакша 396 | інакшої 397 | інакшій 398 | інакшу 399 | інакшою 400 | інакші 401 | інакших 402 | інакшими 403 | інколи 404 | іноді 405 | інше 406 | іншого 407 | іншому 408 | іншим 409 | інший 410 | іншім 411 | інша 412 | іншої 413 | іншій 414 | іншу 415 | іншою 416 | інші 417 | інших 418 | іншими 419 | іще 420 | їхній 421 | їхнього 422 | їхньому 423 | їхнім 424 | їхня 425 | їхньої 426 | їхню 427 | їхньою 428 | їхнє 429 | їхні 430 | їхніх 431 | їхніми 432 | й 433 | кілька 434 | кількох 435 | кільком 436 | кількома 437 | кінець 438 | кожний 439 | кожного 440 | кожному 441 | кожним 442 | кожнім 443 | кожна 444 | кожної 445 | кожній 446 | кожну 447 | кожною 448 | кожне 449 | кожні 450 | кожних 451 | кожними 452 | кожен 453 | кожнісінький 454 | кожнісінького 455 | кожнісінькому 456 | кожнісіньким 457 | кожнісінькім 458 | кожнісінька 459 | кожнісінької 460 | кожнісінькій 461 | кожнісіньку 462 | кожнісінькою 463 | кожнісіньке 464 | кожнісінькі 465 | кожнісіньких 466 | кожнісінькими 467 | коли 468 | колись 469 | коло 470 | котрий 471 | котрого 472 | котрому 473 | котрим 474 | котрім 475 | котра 476 | котрої 477 | котрій 478 | котру 479 | котрою 480 | котре 481 | котрі 482 | котрих 483 | котрими 484 | котрийсь 485 | котрогось 486 | котромусь 487 | котримось 488 | котримсь 489 | котрімсь 490 | котрась 491 | котроїсь 492 | котрійсь 493 | котрусь 494 | котроюсь 495 | котресь 496 | котрісь 497 | котрихось 498 | котрихсь 499 | котримись 500 | край 501 | крізь 502 | крім 503 | круг 504 | кругом 505 | куди 506 | кудись 507 | кудою 508 | ледве 509 | ледь 510 | лиш 511 | лише 512 | лишень 513 | мерсі 514 | ми 515 | нас 516 | нам 517 | нами 518 | між 519 | мій 520 | мого 521 | моєму 522 | моїм 523 | моя 524 | моєї 525 | моїй 526 | мою 527 | моєю 528 | моє 529 | мої 530 | моїх 531 | моїми 532 | мов 533 | мовби 534 | мовбито 535 | могти 536 | можіть 537 | можу 538 | можеш 539 | може 540 | можем 541 | можемо 542 | можете 543 | можуть 544 | міг 545 | могла 546 | могло 547 | могли 548 | можна 549 | на 550 | навіть 551 | навіщо 552 | навіщось 553 | навколо 554 | навкруг 555 | навпаки 556 | навперейми 557 | навпроти 558 | над 559 | наді 560 | надо 561 | наперед 562 | напередодні 563 | наперекір 564 | напереріз 565 | наприкінці 566 | напроти 567 | насеред 568 | насупроти 569 | нате 570 | наче 571 | начеб 572 | начебто 573 | наш 574 | нашого 575 | нашому 576 | нашим 577 | нашім 578 | наша 579 | нашої 580 | нашій 581 | нашу 582 | нашою 583 | наше 584 | наші 585 | наших 586 | нашими 587 | не 588 | неабищо 589 | неабичого 590 | неабичому 591 | неабичим 592 | небагато 593 | небагатьох 594 | небагатьом 595 | небагатьма 596 | невважаючи 597 | невже 598 | незважаючи 599 | немов 600 | немовби 601 | немовбито 602 | неначе 603 | неначебто 604 | нехай 605 | нижче 606 | ні 607 | ніби 608 | нібито 609 | ніде 610 | ніж 611 | нізащо 612 | нізвідки 613 | нізвідкіля 614 | ніким 615 | нікогісінько 616 | нікого 617 | ніколи 618 | нікому 619 | нікотрий 620 | нікотрого 621 | нікотрому 622 | нікотрим 623 | нікотрім 624 | нікотра 625 | нікотрої 626 | нікотрій 627 | нікотру 628 | нікотрою 629 | нікотре 630 | нікотрі 631 | нікотрих 632 | нікотрими 633 | нікуди 634 | нінащо 635 | ніскільки 636 | ніхто 637 | нічий 638 | нічийого 639 | нічиєму 640 | нічийому 641 | нічиїм 642 | нічия 643 | нічиєї 644 | нічиїй 645 | нічию 646 | нічиєю 647 | нічиє 648 | нічиї 649 | нічиїх 650 | нічиїми 651 | нічийний 652 | нічийного 653 | нічийному 654 | нічийним 655 | нічийнім 656 | нічийна 657 | нічийної 658 | нічийній 659 | нічийну 660 | нічийною 661 | нічийне 662 | нічийні 663 | нічийних 664 | нічийними 665 | нічим 666 | нічого 667 | нічому 668 | ніщо 669 | ніяк 670 | ніякий 671 | ніякого 672 | ніякому 673 | ніяким 674 | ніякім 675 | ніяка 676 | ніякої 677 | ніякій 678 | ніяку 679 | ніякою 680 | ніяке 681 | ніякі 682 | ніяких 683 | ніякими 684 | ніякісінький 685 | ніякісінького 686 | ніякісінькому 687 | ніякісіньким 688 | ніякісінькім 689 | ніякісінька 690 | ніякісінької 691 | ніякісінькій 692 | ніякісіньку 693 | ніякісінькою 694 | ніякісіньке 695 | ніякісінькі 696 | ніякісіньких 697 | ніякісінькими 698 | но 699 | ну 700 | нумо 701 | нумте 702 | о 703 | об 704 | обабіч 705 | обік 706 | обіч 707 | од 708 | один 709 | одного 710 | одному 711 | одним 712 | однім 713 | одна 714 | однієї 715 | одної 716 | одній 717 | одну 718 | однією 719 | одною 720 | одне 721 | одно 722 | одні 723 | одних 724 | одними 725 | однак 726 | одначе 727 | окрай 728 | окрім 729 | округ 730 | округи 731 | он 732 | онде 733 | онно 734 | оно 735 | опісля 736 | опріч 737 | осе 738 | осісьо 739 | оскільки 740 | ось 741 | от 742 | отак 743 | отакий 744 | отакого 745 | отакому 746 | отаким 747 | отакім 748 | отака 749 | отакої 750 | отакій 751 | отаку 752 | отакою 753 | отаке 754 | отакі 755 | отаких 756 | отакими 757 | отакісінький 758 | отакісінького 759 | отакісінькому 760 | отакісіньким 761 | отакісінькім 762 | отакісінька 763 | отакісінької 764 | отакісінькій 765 | отакісіньку 766 | отакісінькою 767 | отакісіньке 768 | отакісінькі 769 | отакісіньких 770 | отакісінькими 771 | отам 772 | отже 773 | ото 774 | отож 775 | отой 776 | отого 777 | отому 778 | отим 779 | отім 780 | ота 781 | отієї 782 | отої 783 | отій 784 | оту 785 | отією 786 | отою 787 | оте 788 | оті 789 | отих 790 | отими 791 | отсе 792 | оттак 793 | отто 794 | отут 795 | оце 796 | оцей 797 | оцього 798 | оцьому 799 | оцим 800 | оцім 801 | оця 802 | оцієї 803 | оцій 804 | оцю 805 | оцією 806 | оці 807 | оцих 808 | оцими 809 | пак 810 | перед 811 | перетакий 812 | перетакого 813 | перетакому 814 | перетаким 815 | перетакім 816 | перетака 817 | перетакої 818 | перетакій 819 | перетаку 820 | перетакою 821 | перетаке 822 | перетакі 823 | перетаких 824 | перетакими 825 | під 826 | підо 827 | після 828 | по 829 | побік 830 | побіч 831 | поблизу 832 | поверх 833 | повз 834 | повздовж 835 | повсюди 836 | повсюдно 837 | подекуди 838 | подеякий 839 | подеякого 840 | подеякому 841 | подеяким 842 | подеякім 843 | подеяка 844 | подеякої 845 | подеякій 846 | подеяку 847 | подеякою 848 | подеяке 849 | подеякі 850 | подеяких 851 | подеякими 852 | подовж 853 | поза 854 | позад 855 | позаду 856 | позатой 857 | позатого 858 | позатому 859 | позатим 860 | позатім 861 | позата 862 | позатієї 863 | позатої 864 | позатій 865 | позату 866 | позатією 867 | позатою 868 | позате 869 | позаті 870 | позатих 871 | позатими 872 | позаяк 873 | поздовж 874 | поки 875 | покіль 876 | покрай 877 | поміж 878 | понад 879 | понадо 880 | понижче 881 | поперед 882 | попереду 883 | поперек 884 | попід 885 | попліч 886 | попри 887 | попросту 888 | поруч 889 | поряд 890 | посеред 891 | посередині 892 | потім 893 | поуз 894 | прецінь 895 | при 896 | притому 897 | причім 898 | причому 899 | про 900 | проміж 901 | просто 902 | проте 903 | проти 904 | протягом 905 | раз 906 | раніше 907 | сам 908 | самого 909 | самому 910 | самим 911 | самім 912 | сама 913 | самої 914 | самій 915 | саму 916 | самою 917 | саме 918 | само 919 | сами 920 | самі 921 | самих 922 | самими 923 | самий 924 | свій 925 | свого 926 | своєму 927 | своїм 928 | своя 929 | своєї 930 | своїй 931 | свою 932 | своєю 933 | своє 934 | свої 935 | своїх 936 | своїми 937 | се 938 | себе 939 | собі 940 | собою 941 | себто 942 | серед 943 | сиріч 944 | скільки 945 | скількох 946 | скільком 947 | скількома 948 | скількись 949 | скількохось 950 | скількохсь 951 | скількомось 952 | скількомсь 953 | скількомась 954 | скрізь 955 | спереду 956 | справді 957 | стільки 958 | стількох 959 | стільком 960 | стількома 961 | супроти 962 | супротив 963 | сюди 964 | сякий 965 | сякого 966 | сякому 967 | сяким 968 | сякім 969 | сяка 970 | сякої 971 | сякій 972 | сяку 973 | сякою 974 | сяке 975 | сякі 976 | сяких 977 | сякими 978 | та 979 | так 980 | такенний 981 | такенного 982 | такенному 983 | такенним 984 | такеннім 985 | такенна 986 | такенної 987 | такенній 988 | такенну 989 | такенною 990 | такенне 991 | такенні 992 | такенних 993 | такенними 994 | таки 995 | такий 996 | такого 997 | такому 998 | таким 999 | такім 1000 | така 1001 | такої 1002 | такій 1003 | таку 1004 | такою 1005 | таке 1006 | такі 1007 | таких 1008 | такими 1009 | такісінький 1010 | такісінького 1011 | такісінькому 1012 | такісіньким 1013 | такісінькім 1014 | такісінька 1015 | такісінької 1016 | такісінькій 1017 | такісіньку 1018 | такісінькою 1019 | такісіньке 1020 | такісінькі 1021 | такісіньких 1022 | такісінькими 1023 | також 1024 | там 1025 | тамки 1026 | тамтой 1027 | тамтого 1028 | тамтому 1029 | тамтим 1030 | тамтім 1031 | тамта 1032 | тамтієї 1033 | тамтої 1034 | тамтій 1035 | тамту 1036 | тамтією 1037 | тамтою 1038 | тамте 1039 | тамті 1040 | тамтих 1041 | тамтими 1042 | твій 1043 | твого 1044 | твоєму 1045 | твоїм 1046 | твоя 1047 | твоєї 1048 | твоїй 1049 | твою 1050 | твоєю 1051 | твоє 1052 | твої 1053 | твоїх 1054 | твоїми 1055 | те 1056 | того 1057 | тому 1058 | тим 1059 | тім 1060 | теє 1061 | теж 1062 | тепер 1063 | теперечки 1064 | ти 1065 | тебе 1066 | тобі 1067 | тобою 1068 | тільки 1069 | то 1070 | тобто 1071 | тоді 1072 | тож 1073 | той 1074 | тієї 1075 | тої 1076 | тій 1077 | ту 1078 | тією 1079 | тою 1080 | ті 1081 | тих 1082 | тими 1083 | тощо 1084 | туди 1085 | тудою 1086 | тут 1087 | тутеньки 1088 | тутечки 1089 | тутки 1090 | у 1091 | ув 1092 | увесь 1093 | усього 1094 | усьому 1095 | усім 1096 | уся 1097 | усієї 1098 | усій 1099 | усю 1100 | усією 1101 | усе 1102 | усі 1103 | усіх 1104 | усіма 1105 | уві 1106 | угу 1107 | уздовж 1108 | унаслідок 1109 | уподовж 1110 | упоперек 1111 | упродовж 1112 | усілякий 1113 | усілякого 1114 | усілякому 1115 | усіляким 1116 | усілякім 1117 | усіляка 1118 | усілякої 1119 | усілякій 1120 | усіляку 1121 | усілякою 1122 | усіляке 1123 | усілякі 1124 | усіляких 1125 | усілякими 1126 | услід 1127 | усупереч 1128 | усюди 1129 | усякий 1130 | усякого 1131 | усякому 1132 | усяким 1133 | усякім 1134 | усяка 1135 | усякої 1136 | усякій 1137 | усяку 1138 | усякою 1139 | усяке 1140 | усякі 1141 | усяких 1142 | усякими 1143 | усяк 1144 | утім 1145 | хай 1146 | хіба 1147 | хоч 1148 | хоча 1149 | хто 1150 | кого 1151 | кому 1152 | ким 1153 | кім 1154 | хтось 1155 | когось 1156 | комусь 1157 | кимось 1158 | кимсь 1159 | кімось 1160 | кімсь 1161 | це 1162 | цього 1163 | цьому 1164 | цим 1165 | цім 1166 | цебто 1167 | цей 1168 | ця 1169 | цієї 1170 | цій 1171 | цю 1172 | цією 1173 | ці 1174 | цих 1175 | цими 1176 | чень 1177 | через 1178 | чи 1179 | чий 1180 | чийого 1181 | чиєму 1182 | чийому 1183 | чиїм 1184 | чия 1185 | чиєї 1186 | чиїй 1187 | чию 1188 | чиєю 1189 | чиє 1190 | чиї 1191 | чиїх 1192 | чиїми 1193 | чийсь 1194 | чийогось 1195 | чиємусь 1196 | чийомусь 1197 | чиїмось 1198 | чиїмсь 1199 | чиясь 1200 | чиєїсь 1201 | чиїйсь 1202 | чиюсь 1203 | чиєюсь 1204 | чиєсь 1205 | чиїсь 1206 | чиїхось 1207 | чиїхсь 1208 | чиїмись 1209 | чому 1210 | чомусь 1211 | чортзна 1212 | шляхом 1213 | ще 1214 | що 1215 | чого 1216 | віщо 1217 | чим 1218 | чім 1219 | щоб 1220 | щоби 1221 | щодо 1222 | щойно 1223 | щоправда 1224 | щось 1225 | чогось 1226 | віщось 1227 | чимось 1228 | чимсь 1229 | чімось 1230 | чімсь 1231 | я 1232 | мене 1233 | мені 1234 | мною 1235 | як 1236 | якби 1237 | який 1238 | якого 1239 | якому 1240 | яким 1241 | якім 1242 | яка 1243 | якої 1244 | якій 1245 | яку 1246 | якою 1247 | яке 1248 | які 1249 | яких 1250 | якими 1251 | якийсь 1252 | якогось 1253 | якомусь 1254 | якимось 1255 | якимсь 1256 | якімсь 1257 | якась 1258 | якоїсь 1259 | якійсь 1260 | якусь 1261 | якоюсь 1262 | якесь 1263 | якісь 1264 | якихось 1265 | якихсь 1266 | якимись 1267 | якось 1268 | якраз 1269 | якщо -------------------------------------------------------------------------------- /src/test/resources/stopwords.txt: -------------------------------------------------------------------------------- 1 | а 2 | аби 3 | абиде 4 | абиколи 5 | абикуди 6 | абихто 7 | абикого 8 | абикому 9 | абиким 10 | абичий 11 | абичийого 12 | абичиєму 13 | абичийому 14 | абичиїм 15 | абичия 16 | абичиєї 17 | абичиїй 18 | абичию 19 | абичиєю 20 | абичиє 21 | абичиї 22 | абичиїх 23 | абичиїми 24 | абищо 25 | абичого 26 | абичому 27 | абичим 28 | абиякий 29 | абиякого 30 | абиякому 31 | абияким 32 | абиякім 33 | абияка 34 | абиякої 35 | абиякій 36 | абияку 37 | абиякою 38 | абияке 39 | абиякі 40 | абияких 41 | абиякими 42 | або 43 | абощо 44 | авжеж 45 | авось 46 | ага 47 | адже 48 | аж 49 | ажень 50 | але 51 | амінь 52 | ані 53 | аніде 54 | аніж 55 | анізащо 56 | анікогісінько 57 | аніколи 58 | аніскільки 59 | аніхто 60 | анікого 61 | анікому 62 | аніким 63 | анічогісінько 64 | аніщо 65 | анічого 66 | анічому 67 | анічим 68 | аніякий 69 | аніякого 70 | аніякому 71 | аніяким 72 | аніякім 73 | аніяка 74 | аніякої 75 | аніякій 76 | аніяку 77 | аніякою 78 | аніяке 79 | аніякі 80 | аніяких 81 | аніякими 82 | аніякісенький 83 | аніякісенького 84 | аніякісенькому 85 | аніякісеньким 86 | аніякісенькім 87 | аніякісенька 88 | аніякісенької 89 | аніякісенькій 90 | аніякісеньку 91 | аніякісенькою 92 | аніякісеньке 93 | аніякісенькі 94 | аніякісеньких 95 | аніякісенькими 96 | аніякісінький 97 | аніякісінького 98 | аніякісінькому 99 | аніякісіньким 100 | аніякісінькім 101 | аніякісінька 102 | аніякісінької 103 | аніякісінькій 104 | аніякісіньку 105 | аніякісінькою 106 | аніякісіньке 107 | аніякісінькі 108 | аніякісіньких 109 | аніякісінькими 110 | ану 111 | ато 112 | атож 113 | ач 114 | ачей 115 | аякже 116 | б 117 | ба 118 | багато 119 | багатьох 120 | багатьом 121 | багатьма 122 | без 123 | би 124 | біля 125 | бо 126 | бодай 127 | бути 128 | будь 129 | будьмо 130 | будьте 131 | є 132 | єси 133 | суть 134 | буду 135 | будеш 136 | буде 137 | будем 138 | будемо 139 | будете 140 | будуть 141 | був 142 | була 143 | було 144 | були 145 | буцім 146 | буцімто 147 | в 148 | ваш 149 | вашого 150 | вашому 151 | вашим 152 | вашім 153 | ваша 154 | вашої 155 | вашій 156 | вашу 157 | вашою 158 | ваше 159 | ваші 160 | ваших 161 | вашими 162 | ввесь 163 | всього 164 | всьому 165 | всім 166 | вся 167 | всієї 168 | всій 169 | всю 170 | всією 171 | все 172 | всі 173 | всіх 174 | всіма 175 | вві 176 | весь 177 | вздовж 178 | ви 179 | вас 180 | вам 181 | вами 182 | ві 183 | від 184 | відколи 185 | відповідно 186 | відтепер 187 | відтоді 188 | він 189 | його 190 | нього 191 | йому 192 | ним 193 | нім 194 | ньому 195 | власне 196 | властиво 197 | внаслідок 198 | вона 199 | її 200 | неї 201 | їй 202 | нею 203 | ній 204 | вони 205 | їх 206 | них 207 | їм 208 | ними 209 | воно 210 | вподовж 211 | впоперек 212 | впродовж 213 | всілякий 214 | всілякого 215 | всілякому 216 | всіляким 217 | всілякім 218 | всіляка 219 | всілякої 220 | всілякій 221 | всіляку 222 | всілякою 223 | всіляке 224 | всілякі 225 | всіляких 226 | всілякими 227 | вслід 228 | всупереч 229 | всюди 230 | всякий 231 | всякого 232 | всякому 233 | всяким 234 | всякім 235 | всяка 236 | всякої 237 | всякій 238 | всяку 239 | всякою 240 | всяке 241 | всякі 242 | всяких 243 | всякими 244 | всяк 245 | втім 246 | гаразд 247 | ге 248 | геть 249 | де 250 | дедалі 251 | деінде 252 | декілька 253 | декількох 254 | декільком 255 | декількома 256 | деколи 257 | декотрий 258 | декотрого 259 | декотрому 260 | декотрим 261 | декотрім 262 | декотра 263 | декотрої 264 | декотрій 265 | декотру 266 | декотрою 267 | декотре 268 | декотрі 269 | декотрих 270 | декотрими 271 | десь 272 | дехто 273 | декого 274 | декому 275 | деким 276 | декім 277 | дечий 278 | дечийого 279 | дечиєму 280 | дечийому 281 | дечиїм 282 | дечия 283 | дечиєї 284 | дечиїй 285 | дечию 286 | дечиєю 287 | дечиє 288 | дечиї 289 | дечиїх 290 | дечиїми 291 | дещо 292 | дечого 293 | дечому 294 | дечим 295 | дечім 296 | деякий 297 | деякого 298 | деякому 299 | деяким 300 | деякім 301 | деяка 302 | деякої 303 | деякій 304 | деяку 305 | деякою 306 | деяке 307 | деякі 308 | деяких 309 | деякими 310 | для 311 | до 312 | довкола 313 | доки 314 | допіру 315 | допоки 316 | досі 317 | дотепер 318 | доти 319 | еге 320 | ж 321 | же 322 | жодний 323 | жодного 324 | жодному 325 | жодним 326 | жоднім 327 | жодна 328 | жодної 329 | жодній 330 | жодну 331 | жодною 332 | жодне 333 | жодні 334 | жодних 335 | жодними 336 | жоден 337 | жоднісінький 338 | жоднісінького 339 | жоднісінькому 340 | жоднісіньким 341 | жоднісінькім 342 | жоднісінька 343 | жоднісінької 344 | жоднісінькій 345 | жоднісіньку 346 | жоднісінькою 347 | жоднісіньке 348 | жоднісінькі 349 | жоднісіньких 350 | жоднісінькими 351 | з 352 | за 353 | завгодно 354 | завдяки 355 | завжди 356 | завше 357 | задля 358 | залежно 359 | замість 360 | заради 361 | зараз 362 | зате 363 | зверху 364 | звідки 365 | звідкилясь 366 | звідкись 367 | звідкіль 368 | звідкіля 369 | звідкілясь 370 | звідси 371 | звідсіль 372 | звідсіля 373 | звідти 374 | звідтіль 375 | звідтіля 376 | звідусіль 377 | звідусюди 378 | звідціля 379 | здовж 380 | ззаду 381 | зі 382 | зо 383 | зсередини 384 | ич 385 | і 386 | ібн 387 | із 388 | ізсередини 389 | інакше 390 | інакший 391 | інакшого 392 | інакшому 393 | інакшим 394 | інакшім 395 | інакша 396 | інакшої 397 | інакшій 398 | інакшу 399 | інакшою 400 | інакші 401 | інакших 402 | інакшими 403 | інколи 404 | іноді 405 | інше 406 | іншого 407 | іншому 408 | іншим 409 | інший 410 | іншім 411 | інша 412 | іншої 413 | іншій 414 | іншу 415 | іншою 416 | інші 417 | інших 418 | іншими 419 | іще 420 | їхній 421 | їхнього 422 | їхньому 423 | їхнім 424 | їхня 425 | їхньої 426 | їхню 427 | їхньою 428 | їхнє 429 | їхні 430 | їхніх 431 | їхніми 432 | й 433 | кілька 434 | кількох 435 | кільком 436 | кількома 437 | кінець 438 | кожний 439 | кожного 440 | кожному 441 | кожним 442 | кожнім 443 | кожна 444 | кожної 445 | кожній 446 | кожну 447 | кожною 448 | кожне 449 | кожні 450 | кожних 451 | кожними 452 | кожен 453 | кожнісінький 454 | кожнісінького 455 | кожнісінькому 456 | кожнісіньким 457 | кожнісінькім 458 | кожнісінька 459 | кожнісінької 460 | кожнісінькій 461 | кожнісіньку 462 | кожнісінькою 463 | кожнісіньке 464 | кожнісінькі 465 | кожнісіньких 466 | кожнісінькими 467 | коли 468 | колись 469 | коло 470 | котрий 471 | котрого 472 | котрому 473 | котрим 474 | котрім 475 | котра 476 | котрої 477 | котрій 478 | котру 479 | котрою 480 | котре 481 | котрі 482 | котрих 483 | котрими 484 | котрийсь 485 | котрогось 486 | котромусь 487 | котримось 488 | котримсь 489 | котрімсь 490 | котрась 491 | котроїсь 492 | котрійсь 493 | котрусь 494 | котроюсь 495 | котресь 496 | котрісь 497 | котрихось 498 | котрихсь 499 | котримись 500 | край 501 | крізь 502 | крім 503 | круг 504 | кругом 505 | куди 506 | кудись 507 | кудою 508 | ледве 509 | ледь 510 | лиш 511 | лише 512 | лишень 513 | мерсі 514 | ми 515 | нас 516 | нам 517 | нами 518 | між 519 | мій 520 | мого 521 | моєму 522 | моїм 523 | моя 524 | моєї 525 | моїй 526 | мою 527 | моєю 528 | моє 529 | мої 530 | моїх 531 | моїми 532 | мов 533 | мовби 534 | мовбито 535 | могти 536 | можіть 537 | можу 538 | можеш 539 | може 540 | можем 541 | можемо 542 | можете 543 | можуть 544 | міг 545 | могла 546 | могло 547 | могли 548 | можна 549 | на 550 | навіть 551 | навіщо 552 | навіщось 553 | навколо 554 | навкруг 555 | навпаки 556 | навперейми 557 | навпроти 558 | над 559 | наді 560 | надо 561 | наперед 562 | напередодні 563 | наперекір 564 | напереріз 565 | наприкінці 566 | напроти 567 | насеред 568 | насупроти 569 | нате 570 | наче 571 | начеб 572 | начебто 573 | наш 574 | нашого 575 | нашому 576 | нашим 577 | нашім 578 | наша 579 | нашої 580 | нашій 581 | нашу 582 | нашою 583 | наше 584 | наші 585 | наших 586 | нашими 587 | не 588 | неабищо 589 | неабичого 590 | неабичому 591 | неабичим 592 | небагато 593 | небагатьох 594 | небагатьом 595 | небагатьма 596 | невважаючи 597 | невже 598 | незважаючи 599 | немов 600 | немовби 601 | немовбито 602 | неначе 603 | неначебто 604 | нехай 605 | нижче 606 | ні 607 | ніби 608 | нібито 609 | ніде 610 | ніж 611 | нізащо 612 | нізвідки 613 | нізвідкіля 614 | ніким 615 | нікогісінько 616 | нікого 617 | ніколи 618 | нікому 619 | нікотрий 620 | нікотрого 621 | нікотрому 622 | нікотрим 623 | нікотрім 624 | нікотра 625 | нікотрої 626 | нікотрій 627 | нікотру 628 | нікотрою 629 | нікотре 630 | нікотрі 631 | нікотрих 632 | нікотрими 633 | нікуди 634 | нінащо 635 | ніскільки 636 | ніхто 637 | нічий 638 | нічийого 639 | нічиєму 640 | нічийому 641 | нічиїм 642 | нічия 643 | нічиєї 644 | нічиїй 645 | нічию 646 | нічиєю 647 | нічиє 648 | нічиї 649 | нічиїх 650 | нічиїми 651 | нічийний 652 | нічийного 653 | нічийному 654 | нічийним 655 | нічийнім 656 | нічийна 657 | нічийної 658 | нічийній 659 | нічийну 660 | нічийною 661 | нічийне 662 | нічийні 663 | нічийних 664 | нічийними 665 | нічим 666 | нічого 667 | нічому 668 | ніщо 669 | ніяк 670 | ніякий 671 | ніякого 672 | ніякому 673 | ніяким 674 | ніякім 675 | ніяка 676 | ніякої 677 | ніякій 678 | ніяку 679 | ніякою 680 | ніяке 681 | ніякі 682 | ніяких 683 | ніякими 684 | ніякісінький 685 | ніякісінького 686 | ніякісінькому 687 | ніякісіньким 688 | ніякісінькім 689 | ніякісінька 690 | ніякісінької 691 | ніякісінькій 692 | ніякісіньку 693 | ніякісінькою 694 | ніякісіньке 695 | ніякісінькі 696 | ніякісіньких 697 | ніякісінькими 698 | но 699 | ну 700 | нумо 701 | нумте 702 | о 703 | об 704 | обабіч 705 | обік 706 | обіч 707 | од 708 | один 709 | одного 710 | одному 711 | одним 712 | однім 713 | одна 714 | однієї 715 | одної 716 | одній 717 | одну 718 | однією 719 | одною 720 | одне 721 | одно 722 | одні 723 | одних 724 | одними 725 | однак 726 | одначе 727 | окрай 728 | окрім 729 | округ 730 | округи 731 | он 732 | онде 733 | онно 734 | оно 735 | опісля 736 | опріч 737 | осе 738 | осісьо 739 | оскільки 740 | ось 741 | от 742 | отак 743 | отакий 744 | отакого 745 | отакому 746 | отаким 747 | отакім 748 | отака 749 | отакої 750 | отакій 751 | отаку 752 | отакою 753 | отаке 754 | отакі 755 | отаких 756 | отакими 757 | отакісінький 758 | отакісінького 759 | отакісінькому 760 | отакісіньким 761 | отакісінькім 762 | отакісінька 763 | отакісінької 764 | отакісінькій 765 | отакісіньку 766 | отакісінькою 767 | отакісіньке 768 | отакісінькі 769 | отакісіньких 770 | отакісінькими 771 | отам 772 | отже 773 | ото 774 | отож 775 | отой 776 | отого 777 | отому 778 | отим 779 | отім 780 | ота 781 | отієї 782 | отої 783 | отій 784 | оту 785 | отією 786 | отою 787 | оте 788 | оті 789 | отих 790 | отими 791 | отсе 792 | оттак 793 | отто 794 | отут 795 | оце 796 | оцей 797 | оцього 798 | оцьому 799 | оцим 800 | оцім 801 | оця 802 | оцієї 803 | оцій 804 | оцю 805 | оцією 806 | оці 807 | оцих 808 | оцими 809 | пак 810 | перед 811 | перетакий 812 | перетакого 813 | перетакому 814 | перетаким 815 | перетакім 816 | перетака 817 | перетакої 818 | перетакій 819 | перетаку 820 | перетакою 821 | перетаке 822 | перетакі 823 | перетаких 824 | перетакими 825 | під 826 | підо 827 | після 828 | по 829 | побік 830 | побіч 831 | поблизу 832 | поверх 833 | повз 834 | повздовж 835 | повсюди 836 | повсюдно 837 | подекуди 838 | подеякий 839 | подеякого 840 | подеякому 841 | подеяким 842 | подеякім 843 | подеяка 844 | подеякої 845 | подеякій 846 | подеяку 847 | подеякою 848 | подеяке 849 | подеякі 850 | подеяких 851 | подеякими 852 | подовж 853 | поза 854 | позад 855 | позаду 856 | позатой 857 | позатого 858 | позатому 859 | позатим 860 | позатім 861 | позата 862 | позатієї 863 | позатої 864 | позатій 865 | позату 866 | позатією 867 | позатою 868 | позате 869 | позаті 870 | позатих 871 | позатими 872 | позаяк 873 | поздовж 874 | поки 875 | покіль 876 | покрай 877 | поміж 878 | понад 879 | понадо 880 | понижче 881 | поперед 882 | попереду 883 | поперек 884 | попід 885 | попліч 886 | попри 887 | попросту 888 | поруч 889 | поряд 890 | посеред 891 | посередині 892 | потім 893 | поуз 894 | прецінь 895 | при 896 | притому 897 | причім 898 | причому 899 | про 900 | проміж 901 | просто 902 | проте 903 | проти 904 | протягом 905 | раз 906 | раніше 907 | сам 908 | самого 909 | самому 910 | самим 911 | самім 912 | сама 913 | самої 914 | самій 915 | саму 916 | самою 917 | саме 918 | само 919 | сами 920 | самі 921 | самих 922 | самими 923 | самий 924 | свій 925 | свого 926 | своєму 927 | своїм 928 | своя 929 | своєї 930 | своїй 931 | свою 932 | своєю 933 | своє 934 | свої 935 | своїх 936 | своїми 937 | се 938 | себе 939 | собі 940 | собою 941 | себто 942 | серед 943 | сиріч 944 | скільки 945 | скількох 946 | скільком 947 | скількома 948 | скількись 949 | скількохось 950 | скількохсь 951 | скількомось 952 | скількомсь 953 | скількомась 954 | скрізь 955 | спереду 956 | справді 957 | стільки 958 | стількох 959 | стільком 960 | стількома 961 | супроти 962 | супротив 963 | сюди 964 | сякий 965 | сякого 966 | сякому 967 | сяким 968 | сякім 969 | сяка 970 | сякої 971 | сякій 972 | сяку 973 | сякою 974 | сяке 975 | сякі 976 | сяких 977 | сякими 978 | та 979 | так 980 | такенний 981 | такенного 982 | такенному 983 | такенним 984 | такеннім 985 | такенна 986 | такенної 987 | такенній 988 | такенну 989 | такенною 990 | такенне 991 | такенні 992 | такенних 993 | такенними 994 | таки 995 | такий 996 | такого 997 | такому 998 | таким 999 | такім 1000 | така 1001 | такої 1002 | такій 1003 | таку 1004 | такою 1005 | таке 1006 | такі 1007 | таких 1008 | такими 1009 | такісінький 1010 | такісінького 1011 | такісінькому 1012 | такісіньким 1013 | такісінькім 1014 | такісінька 1015 | такісінької 1016 | такісінькій 1017 | такісіньку 1018 | такісінькою 1019 | такісіньке 1020 | такісінькі 1021 | такісіньких 1022 | такісінькими 1023 | також 1024 | там 1025 | тамки 1026 | тамтой 1027 | тамтого 1028 | тамтому 1029 | тамтим 1030 | тамтім 1031 | тамта 1032 | тамтієї 1033 | тамтої 1034 | тамтій 1035 | тамту 1036 | тамтією 1037 | тамтою 1038 | тамте 1039 | тамті 1040 | тамтих 1041 | тамтими 1042 | твій 1043 | твого 1044 | твоєму 1045 | твоїм 1046 | твоя 1047 | твоєї 1048 | твоїй 1049 | твою 1050 | твоєю 1051 | твоє 1052 | твої 1053 | твоїх 1054 | твоїми 1055 | те 1056 | того 1057 | тому 1058 | тим 1059 | тім 1060 | теє 1061 | теж 1062 | тепер 1063 | теперечки 1064 | ти 1065 | тебе 1066 | тобі 1067 | тобою 1068 | тільки 1069 | то 1070 | тобто 1071 | тоді 1072 | тож 1073 | той 1074 | тієї 1075 | тої 1076 | тій 1077 | ту 1078 | тією 1079 | тою 1080 | ті 1081 | тих 1082 | тими 1083 | тощо 1084 | туди 1085 | тудою 1086 | тут 1087 | тутеньки 1088 | тутечки 1089 | тутки 1090 | у 1091 | ув 1092 | увесь 1093 | усього 1094 | усьому 1095 | усім 1096 | уся 1097 | усієї 1098 | усій 1099 | усю 1100 | усією 1101 | усе 1102 | усі 1103 | усіх 1104 | усіма 1105 | уві 1106 | угу 1107 | уздовж 1108 | унаслідок 1109 | уподовж 1110 | упоперек 1111 | упродовж 1112 | усілякий 1113 | усілякого 1114 | усілякому 1115 | усіляким 1116 | усілякім 1117 | усіляка 1118 | усілякої 1119 | усілякій 1120 | усіляку 1121 | усілякою 1122 | усіляке 1123 | усілякі 1124 | усіляких 1125 | усілякими 1126 | услід 1127 | усупереч 1128 | усюди 1129 | усякий 1130 | усякого 1131 | усякому 1132 | усяким 1133 | усякім 1134 | усяка 1135 | усякої 1136 | усякій 1137 | усяку 1138 | усякою 1139 | усяке 1140 | усякі 1141 | усяких 1142 | усякими 1143 | усяк 1144 | утім 1145 | хай 1146 | хіба 1147 | хоч 1148 | хоча 1149 | хто 1150 | кого 1151 | кому 1152 | ким 1153 | кім 1154 | хтось 1155 | когось 1156 | комусь 1157 | кимось 1158 | кимсь 1159 | кімось 1160 | кімсь 1161 | це 1162 | цього 1163 | цьому 1164 | цим 1165 | цім 1166 | цебто 1167 | цей 1168 | ця 1169 | цієї 1170 | цій 1171 | цю 1172 | цією 1173 | ці 1174 | цих 1175 | цими 1176 | чень 1177 | через 1178 | чи 1179 | чий 1180 | чийого 1181 | чиєму 1182 | чийому 1183 | чиїм 1184 | чия 1185 | чиєї 1186 | чиїй 1187 | чию 1188 | чиєю 1189 | чиє 1190 | чиї 1191 | чиїх 1192 | чиїми 1193 | чийсь 1194 | чийогось 1195 | чиємусь 1196 | чийомусь 1197 | чиїмось 1198 | чиїмсь 1199 | чиясь 1200 | чиєїсь 1201 | чиїйсь 1202 | чиюсь 1203 | чиєюсь 1204 | чиєсь 1205 | чиїсь 1206 | чиїхось 1207 | чиїхсь 1208 | чиїмись 1209 | чому 1210 | чомусь 1211 | чортзна 1212 | шляхом 1213 | ще 1214 | що 1215 | чого 1216 | віщо 1217 | чим 1218 | чім 1219 | щоб 1220 | щоби 1221 | щодо 1222 | щойно 1223 | щоправда 1224 | щось 1225 | чогось 1226 | віщось 1227 | чимось 1228 | чимсь 1229 | чімось 1230 | чімсь 1231 | я 1232 | мене 1233 | мені 1234 | мною 1235 | як 1236 | якби 1237 | який 1238 | якого 1239 | якому 1240 | яким 1241 | якім 1242 | яка 1243 | якої 1244 | якій 1245 | яку 1246 | якою 1247 | яке 1248 | які 1249 | яких 1250 | якими 1251 | якийсь 1252 | якогось 1253 | якомусь 1254 | якимось 1255 | якимсь 1256 | якімсь 1257 | якась 1258 | якоїсь 1259 | якійсь 1260 | якусь 1261 | якоюсь 1262 | якесь 1263 | якісь 1264 | якихось 1265 | якихсь 1266 | якимись 1267 | якось 1268 | якраз 1269 | якщо --------------------------------------------------------------------------------