2012-08-24 3 views
16

Załóżmy, że w moim indeksie elasticsearch mam pole o nazwie "dots", które będzie zawierało ciąg oddzielonych wyrazów interpunkcyjnych (np. "First.second.third").Jak dopasować na prefiksie w Elasticsearch

Muszę wyszukać np. "first.second", a następnie uzyskać wszystkie wpisy, których pole "dots" zawiera ciąg znaków dokładnie "first.second" lub rozpoczynający się od "first.second".

Mam problem ze zrozumieniem sposobu działania zapytań tekstowych, przynajmniej nie udało mi się utworzyć zapytania, które wykonuje zadanie.

Odpowiedz

20

Elasticsearch ma Path Hierarchy Tokenizer, który został stworzony dokładnie dla takiego przypadku użycia. Oto przykład, jak ustawić go do indeksu:

# Create a new index with custom path_hierarchy analyzer 
# See http://www.elasticsearch.org/guide/reference/index-modules/analysis/pathhierarchy-tokenizer.html 
curl -XPUT "localhost:9200/prefix-test" -d '{ 
    "settings": { 
     "analysis": { 
      "analyzer": { 
       "prefix-test-analyzer": { 
        "type": "custom", 
        "tokenizer": "prefix-test-tokenizer" 
       } 
      }, 
      "tokenizer": { 
       "prefix-test-tokenizer": { 
        "type": "path_hierarchy", 
        "delimiter": "." 
       } 
      } 
     } 
    }, 
    "mappings": { 
     "doc": { 
      "properties": { 
       "dots": { 
        "type": "string", 
        "analyzer": "prefix-test-analyzer", 
        //"index_analyzer": "prefix-test-analyzer", //deprecated 
        "search_analyzer": "keyword" 
       } 
      } 
     } 
    } 
}' 
echo 
# Put some test data 
curl -XPUT "localhost:9200/prefix-test/doc/1" -d '{"dots": "first.second.third"}' 
curl -XPUT "localhost:9200/prefix-test/doc/2" -d '{"dots": "first.second.foo-bar"}' 
curl -XPUT "localhost:9200/prefix-test/doc/3" -d '{"dots": "first.baz.something"}' 
curl -XPOST "localhost:9200/prefix-test/_refresh" 
echo 
# Test searches. 
curl -XPOST "localhost:9200/prefix-test/doc/_search?pretty=true" -d '{ 
    "query": { 
     "term": { 
      "dots": "first" 
     } 
    } 
}' 
echo 
curl -XPOST "localhost:9200/prefix-test/doc/_search?pretty=true" -d '{ 
    "query": { 
     "term": { 
      "dots": "first.second" 
     } 
    } 
}' 
echo 
curl -XPOST "localhost:9200/prefix-test/doc/_search?pretty=true" -d '{ 
    "query": { 
     "term": { 
      "dots": "first.second.foo-bar" 
     } 
    } 
}' 
echo 
curl -XPOST "localhost:9200/prefix-test/doc/_search?pretty=true&q=dots:first.second" 
echo 
+0

Niestety, nie widziałem Twojego wpisu do tej pory !! Wielkie dzięki :) Zajrzę do tego, jak tylko dostanę czas! – Stine

+0

Jak wykonać ustawienia i odwzorowania elementów w moim kodzie Java? – Stine

+1

'client.admin() .indices(). PrepareCreate (" test "). AddMapping (" type1 ", mapowanie) .setSettings (ustawienia) .execute(). ActionGet();" – imotov

2

Wystarczy popatrzeć na prefix queries.

$ curl -XGET 'http://localhost:9200/index/type/_search' -d '{ 
    "query" : { 
     "prefix" : { "dots" : "first.second" } 
    } 
}' 
+1

Nie działa, gdy ciąg zawiera znaki interpunkcyjne:/ – Stine

+1

[To] (https://gist.github.com/3457388) działa na nowym indeksie.Czy masz specjalne odwzorowanie na indeksie? Może powinieneś spróbować na nowym, czystym indeksie. – A21z

+0

Czy istnieje jakakolwiek różnica w wydajności między używaniem tokenajarza hierarchii wyszukiwania lub hierarchii ścieżek? –

1

Istnieje również wiele łatwiejszy sposób, jak wskazano w elasticsearch documentation:

wystarczy użyć:

{ 
    "text_phrase_prefix" : { 
     "fieldname" : "yourprefix" 
    } 
} 

lub od 0.19.9:

{ 
    "match_phrase_prefix" : { 
     "fieldname" : "yourprefix" 
    } 
} 

zamiast:

{ 
    "prefix" : { 
     "fieldname" : "yourprefix" 
} 
1

Szukałem podobnego rozwiązania - ale pasujące tylko przedrostek. Znalazłem @ imtov na answer żeby mnie prawie tam, ale na jedną zmianę - przełączanie analizatory wokół:

"mappings": { 
    "doc": { 
     "properties": { 
      "dots": { 
       "type": "string", 
       "analyzer": "keyword", 
       "search_analyzer": "prefix-test-analyzer" 
      } 
     } 
    } 
} 

zamiast

"mappings": { 
    "doc": { 
     "properties": { 
      "dots": { 
       "type": "string", 
       "index_analyzer": "prefix-test-analyzer", 
       "search_analyzer": "keyword" 
      } 
     } 
    } 
} 

ten sposób dodając:

'{"dots": "first.second"}' 
'{"dots": "first.third"}' 

Doda tylko te pełne tokeny, bez przechowania tokenów.

Jednak poszukiwania obu

first.second.anyotherstring 
first.second 

będzie poprawnie powrócić tylko pierwszy wpis:

'{"dots": "first.second"}' 

Niezupełnie co prosiłeś, ale jakoś związane, więc myślałem, że komuś pomóc.