<jupyter_start><jupyter_text>Elastic Client<jupyter_code>from ltr.client import ElasticClient
client = ElasticClient()<jupyter_output><empty_output><jupyter_text>Download & Build Index (run once)If you don't already have the downloaded dependencies; if you don't have TheMovieDB data indexed run this<jupyter_code>def add_collection_name(src_movie, base_doc):
    if 'belongs_to_collection' in src_movie and src_movie['belongs_to_collection'] is not None:
        if 'name' in src_movie['belongs_to_collection']:
            base_doc['collection_name'] = src_movie['belongs_to_collection']['name']
    return base_doc

from ltr.index import rebuild
from ltr.helpers.movies import indexable_movies
from ltr import download

corpus='http://es-learn-to-rank.labs.o19s.com/tmdb.json'
judgments='http://es-learn-to-rank.labs.o19s.com/title_judgments.txt'
download([corpus, judgments], dest='data/');

movies=indexable_movies(movies='data/tmdb.json', enrich=add_collection_name)
rebuild(client, index='tmdb', doc_src=movies)<jupyter_output><empty_output><jupyter_text>Features for movie titlesWe'll be searching movie titles (think searching for a specific movie on Netflix). And we have a set of judgments around the appropriatte movie to return. IE search for "Star Wars" return good star wars matches, in quality order...These cover various aspects of the problem (searching title by phrase, title bm25 score, release date, etc). We'll use this to explore and analyze a simple model<jupyter_code>client.reset_ltr(index='tmdb')

config = {"validation": {
              "index": "tmdb",
              "params": {
                  "keywords": "rambo"
              }
    
           },
           "featureset": {
            "features": [
            {
                "name": "title_phrase",
                "params": ["keywords"],
                "template": {
                    "constant_score": {
                        "filter": {
                            "match_phrase": {"title": "{{keywords}}"}
                        },
                        "boost": 1.0
                    }  
                }
            },
            {
                "name": "title",
                "params": ["keywords"],
                "template": {
                    "constant_score": {
                        "filter": {
                            "match": {"title": "{{keywords}}"}
                        },
                        "boost": 1.0
                    }  
                }
            },
            {
                "name": "title_bm25",
                "params": ["keywords"],
                "template": {
                    "match": {"title": "{{keywords}}"}
                }
            },
            {
                "name": "overview_bm25",
                "params": ["keywords"],
                "template": {
                    "match": {"overview": "{{keywords}}"}
                }
            },
            {
                "name": "overview_phrase_bm25",
                "params": ["keywords"],
                "template": {
                    "match_phrase": {"overview": "{{keywords}}"}
                }
            },
            {
                "name": "title_fuzzy",
                "params": ["keywords"],
                "template": {
                    "match": {"title": 
                                {"query": "{{keywords}}",
                                 "fuzziness": "AUTO"}}
                }
            },
             {
                "name": "release_year",
                "params": [],
                "template": {
                    "function_score": {
                        "field_value_factor": {
                            "field": "release_year",
                            "missing": 2000
                        },
                        "query": { "match_all": {} }
                    }
                }
            },
            {
                "name": "coll_name_bm25",
                "params": ["keywords"],
                "template": {
                    "match": {"collection_name": 
                                {"query": "{{keywords}}"}}
                }
            },
             {
                "name": "coll_name_phrase_bm25",
                "params": ["keywords"],
                "template": {
                    "match_phrase": {"collection_name": 
                                {"query": "{{keywords}}"}}
                }
            }
            
            
            ]
    }}


client.create_featureset(index='tmdb', name='title_rf', ftr_config=config)<jupyter_output><empty_output><jupyter_text>Training Set GenerationLog out features for each of the above queries out to a training set file<jupyter_code>from ltr.log import FeatureLogger
from ltr.judgments import judgments_open
from itertools import groupby

ftr_logger=FeatureLogger(client, index='tmdb', feature_set='title_rf')
with judgments_open('data/title_judgments.txt') as judgment_list:
    for qid, query_judgments in groupby(judgment_list, key=lambda j: j.qid):
        ftr_logger.log_for_qid(judgments=query_judgments, 
                               qid=qid,
                               keywords=judgment_list.keywords(qid))<jupyter_output><empty_output><jupyter_text>Random Feature SelectionsFeature searches are very time consuming for anything other than trivial data. To deal with feature dependencies, one strategy is to select a random subset of features at every decision tree split for consideration. This prevents overfitting and allows feature impacts to give a more accurate impact to how they effect the relevance.<jupyter_code>from ltr.ranklib import kcv
res  = kcv(client,
            training_set=ftr_logger.logged,
            metric2t='NDCG@10',
            leafs=4,
            trees=100,
            ranker=8, # Use a "Random Forests Model"
            frate=0.5,
            bag=1, # Number of ensembles in the forest bag=1, 1 LambdaMART model with random features chosen
            index='tmdb',
            kcv=5,
            features=[1,2,3,4,5,6,7,8,9],
            featureSet='title_rf',
            modelName='title_rf')

print()
print("Impact of each feature on the model")
for ftrId, impact in res.trainingLogs[0].impacts.items():
    print("{} - {}".format(ftrId, impact))
    
    
print("Test NDCG@10 %s" % res.kcvTestAvg)<jupyter_output><empty_output><jupyter_text>Train the model<jupyter_code>from ltr.ranklib import train
res  = train(client,
             training_set=ftr_logger.logged,
             metric2t='NDCG@10',
             leafs=4,
             trees=100,
             ranker=8, # Use a "Random Forests Model"
             frate=0.5,
             bag=3, # Number of ensembles in the forest bag=1, 1 LambdaMART model with random features chosen
             index='tmdb',
             features=[1,2,3,4,5,6,7,8,9],
             featureSet='title_rf',
             modelName='title_rf')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11464326812428079, 'fraction_numerical': 0.010356731875719217, 'mean_word_length': 1.6619448698315467, 'pattern_counts': {'":': 65, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '552991', 'license': 'Apache-2.0', 'n_tokens_mistral': 2004, 'n_tokens_neox': 1840, 'n_words': 428, 'path': 'notebooks/elasticsearch/tmdb/netfix movies-random-forests.ipynb', 'repo_name': 'DmitryKey/hello-ltr', 'size': '6952'}