How to sort on analyzed/tokenized field in Elasticsearch? - sorting

We're storing a title field in our index and want to use the field for two purposes:
We're analyzing with an ngram filter so we can provide autocomplete and instant results
We want to be able to list results using an ASC sort on the title field rather than score.
The index/filter/analyzer is defined like so:
array(
'number_of_shards' => $this->shards,
'number_of_replicas' => $this->replicas,
'analysis' => array(
'filter' => array(
'nGram_filter' => array(
'type' => 'nGram',
'min_gram' => 2,
'max_gram' => 20,
'token_chars' => array('letter','digit','punctuation','symbol')
)
),
'analyzer' => array(
'index_analyzer' => array(
'type' => 'custom',
'tokenizer' =>'whitespace',
'char_filter' => 'html_strip',
'filter' => array('lowercase','asciifolding','nGram_filter')
),
'search_analyzer' => array(
'type' => 'custom',
'tokenizer' =>'whitespace',
'char_filter' => 'html_strip',
'filter' => array('lowercase','asciifolding')
)
)
)
),
The problem we're experiencing is unpredictable results when we Sort on the title field. After doing a little searching, we found this at the end of the sort man page at ElasticSearch... (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_memory_considerations)
For string based types, the field sorted on should not be analyzed / tokenized.
How can we both analyze the field and sort on it later? Do we need to store the field twice with one using not_analyzed in order to sort? Since the field _source is also storing the title value in it's original state, can that not be used to sort on?

You can use the built in concept of Multi Field Type in Elasticsearch.
The multi_field type allows to map several core_types of the same value. This can come very handy, for example, when wanting to map a string type, once when it’s analyzed and once when it’s not_analyzed.
In the Elasticsearch Reference, please look at the String Sorting and Multi Fields guide on how to setup what you need.
Please note that Multi Field mapping configuration has changed between Elasticsearch 0.90.X and 1.X. Use the appropriate following guide based on your version:
0.90 Multi Field Type
1.X Multi Field Type

Related

Laravel elastic search implement soundex

I'm facing an issue on the elastic search that it's not able to search if someone types wrong spelling. I have done some R & D about Soundex. Now I'm facing an issue to implement Soundex on elastic search. Please help me to do that, I've already installed Phonetic Anaalysis plugin on elastic search but how to configure the plugin with elastic search that will work with the search results.
'title' => [
'type' => 'text',
'analyzer' => $language . '_analyzer',
'index' => true,
'norms' => false,
'term_vector' => 'with_positions_offsets',
'fields' => [
'raw' => [
'type' => 'keyword',
'normalizer' => 'lowercase_normalizer',
'index' => true,
'norms' => false,
],
],
],
You need to create a custom analyzer using phonetic token filter and the apply this custom analyzer to your text field.
Alternatively, if you want to search with mistypes you can use fuzzy matches.

After an ajax need to load a field value and create a select_from_array with the range value

Iam trying and not finding a way to load the value from a field and generate a select_from_array based on its range.
For example:
I have 2 select box
Brand -> loads -> Model (using backpack field types, and its working good)
`'type' => 'select2_from_ajax',
'name' => 'camera_model_id',
'entity' => 'camera_model',
'attribute' => 'name',
'data_source' => url('camera-brands'),
'placeholder' => 'Selecione o Modelo',
'minimum_input_length' => 0,
'dependencies' => ['camera_brand_id'],`
But, after the user selects this last selectBox, I need that another field was modified
`'name' => 'channel',
'label' => "Canal da Câmera",
'type' => 'select2_from_array',
'options' => ['' => '',
'01' => '01',
'02' => '02', ...`
So, the options could be filled with the maximum of the field I registered in the Model field database.
Is it possible? or maybe another approach to achieve the solution?
Thanks in advance!
To have an input that depends on the value of another input, you can make both your fields select2_from_ajax.
That way:
you will have the value of all inputs in the controller (the controller that returns the ajax results; then you can return a filtered set of results depending on how the form is filled so far - CategoryController::index() in the documentation example);
you can use the "dependencies" attribute on the selec2_from_ajax fields, so that when one field is reset, both are;
I hope the answer helps someone. Cheers!

Store Taxonomy (Tree of life) with Couchebase, best practice

I previously asked a question about this (How to store a Tree Of Life in MySQL? (Phylum, Class, Order, Family, etc)) and I was using MySQL but after someone suggested using MongoDB, I decided to look around and install Couchbase. (Funny thing, geraldss suggested Couchbase in the comment of my previous question after I installed it).
I will store the Kingdom, Phylum, Class, etc for each fish in a document. But I would also like to have document(s) to help with a multilevel dropdown.
I want the first dropdown to be the 5 Kingdom, and then the next dropdown will populate with the Phylum available for this kingdom., Then the third dropdown will be populate with a list of this Phylum's class, and so on.
Right now I'm trying to find the best practical way to store this.
Should I create 1 single huge document called taxonomy or should I create multiple documents about, let say, each Phylum (still huge documents), or something else?
Little PHP array example to help me create the document(s):
"Fungi" => array(
"type"=>"kingdom",
"origin" => "Latin, derived from Greek - sp(h)onges, sponges",
"description" => "Obtain food through absorption, excrete enzymes for digestion",
"example" => "molds, mushrooms, lichens",
"Phylum" => array(),
),
"Plantae" => array(
"type"=>"kingdom",
"origin" => "Latin - plant",
"description" => "Multicellular organisms that are autotrophic",
"example" => "mosses, ferns, grasses, flowers, trees.",
"Phylum" => array(),
),
"Animalia" => array(
"type"=>"kingdom",
"origin" => "Latin - breath, soul",
"description" => "Multicellular organisms that develop from the fertilization of an egg by a sperm",
"example" => "sponges, worms, insects, fish, birds, humans",
"Phylum" => array( //32 total, 12 here
"Porifera" => array(
"name" => "Porifera",
"type" => "Phylum",
"origin" => "Latin - to bear pores",
"description" => "Sponges",
),
"Cnidaria" => array(
"name" => "Cnidaria",
"type" => "Phylum",
"origin" => "Greek - nettle",
"description" => "",
"Class" => array(
"Hydrozoa" => array(
"name" => "Hydrozoa",
"description" => "Hydras",
"Order" => array( //Multiple Order
"Family" => array( //Multiple Family for each Order
"Genus" => array( //Multiple Genus for each Family
),
),
),
),
What should I do? Would it be a good approach to create one single document? How would you store this?
(Please don't close this question, I'm trying very hard to switch my mind from relational to document-based DB and I'm struggling with this)

Elasticsearch searching in different results

Im using Elasticsearch with laravel and Elasticquent https://github.com/elasticquent/Elasticquent over the Eloquent model.
Each user of my project can search in a different result of objects.
I have for example
$user_books->addToIndex();
Books::search($search);
And the problem is that everytime when someone go to the current step the elasticsearch is filled with his results.And at the end I have a combined result for each user with their books together.. which is a problem.
I need one user to search only into his results.
How can I achieve that? I think that I probably must delete the indexes after search because I dont need them anymore.
And then
There is no need to delete your indexes,
instead you should index the books added by users by building a custom index
of their user_id like this :-
$data = [
'body' => [
'book' => '$book->name',
'user_id' => Auth::user()->id,
],
'index' => 'your application name',
'type' => 'books',
'id' => $book->id,
];
and then you can use custom queries to search for book belonging to that user only like this
$books = Book::searchByQuery(array('match' => array('user_id' => Auth::user()->id)));
Refer to Query based search and Indexing and Mapping section here

Create custom validation for form entity

I am using the form builder to create an choice-field form an entity looking like this:
$form->add(
'existing_items','entity', array(
'label' => 'Artikel aus',
'class' => 'ProjectShoppinglistBundle:Item',
'empty_value' => 'Bitte einen Artikel auswählen',
'property' => 'name',
'query_builder' => function(EntityRepository $er) use ($options) {
return $er->createQueryBuilder('item')
->leftJoin('item.userItems', 'userItem')
->where('userItem.user = ' . $options['attr']['id'])
->orderBy('item.name', 'ASC');
},
'attr' => array(
'class' => 'form-control',
),
));
but I am using jquery to change the content of the dropdown, so I need to change the validation for the field, how can I achieve that the values in the form are valid for all elements in the items-table and not just the one's which are linked to my the userId used in the query?
This is necessary for my approach because I have a second dropdown where the user can define if he wants to see the items on his own list, of other lists or all items
I have already taken a look at this but I still don't really get it how I can use the eventListener to get the desired result.
If someone could give me a useful hint, I would appreciate this very much.

Resources