Thinking Sphinx: Multiple indices for single model? - search

I'm searching in two different modes using Thinking Sphinx:
Full search on a single model for normal search functionality
Full search across all models for autocomplete dropdown functionality
For the sake of this question, let's say I have a Person and a Country model.
When performing regular searches, I want to fetch all people who's name of country name matches the search string. To achieve this, I have added an index on the countries name in the Person index. All well so far.
When searching to populate my autocomplete dropdown, I want to show all countries and all people matching my search string. Here the problem shows up. When doing an Application-Wide search, I now get:
all countries whose name match my search string
all doctors whose name match my search string, and unfortunately...
all doctors who belongs to a country that matches the search string.
The last part makes for some really confusing autocomplete results for the user. Is there any simple way for me to avoid this by using built-in functionality, for example like having two indices on the Person model, and choose which one to use for each kind of search?

I supposed that your models are like the below:
class Person < ActiveRecord::Base
belongs_to :country
define_index
indexes :name
indexes country(:name), :as => country_name
end
end
class Country < ActiveRecord::Base
has_many :people # has_many :persons # depending on your singular/plural case
define_index
indexes :name
end
end
So, you can get the result without having 3(third condition) by executing the query:
ThinkingSphinx.search :conditions => {:name => params[:q]}, :classes => [Person, Country]
But, if you want to create multiple indexes on a model it can be done like the sample below:
class Person < ActiveRecord::Base
belongs_to :country
define_index :my_first_in do
indexes :name
indexes country(:name)
end
define_index :my_second_in do
indexes :name
end
end

sphinx v3 syntax for the answer above:
ThinkingSphinx::Index.define :country, name: "my_first_in", with: :active_record
indexes name
end

Related

Add element in many to many field and preserve order

class Country(Models.Model):
code = models.CharField(max_length=50)
name = models.CharField(max_length=500)
class Meta:
unique_together = (('code', 'name'),)
db_table = 'md_country'
class UserSettings(models.Model):
...
default_countries = models.ManyToManyField(Country, db_table='user_default_countries', related_name='default_countries')
I have two models inside django models, what im trying is when i add Country models to default_countries i want to preserve order. Currently when i append manytomany field django automatically sort by Country name (alphabetical order)
I have this code
# iterate one by one to preserve fetching order
country_models = [Country.objects.get(id=_id) for _id in request.data[default_countries]]
user_settings.default_countries.clear()
for c in country_models:
user_settings.default_countries.add(c)
After this when i inspect user_settings.default_countries i have ordered countries by name in alphabetical order.
I want to preserve when adding element. If i want to add France and Australia and i order the list like that i on the end when i pull data from db i want it to be ordered like that. Now on this example i have Australia then France.
EDIT:
I checked the database and when inserting the data, it insert in right order
For example if i want France(73) then Australia(13), France has smaller id so its inserted first. There is a problem with django when pulling the data from database.
So as I understand correct you want to sort by insert order:
someSetting = UserSettings.objects.first()
countries = someSetting.default_countries.order_by('id')
I found the workaround.
Firstly i defined new property inside model where default_countries is.
#property
def ordered_default_countries(self):
return self.default_countries.all().order_by('-id')
Then in serializer where i serialize this field i just pointed default_countries field to ordered_default_countries.

In ActiveAdmin Select from list of polymorphic items

So I have a list of items you can select multiple from and the list is of to different things (polymorphic) but I'm not sure how to implement this as what I have isn't working.
I've looked but I can't seem to find anything on this, only on how to filter polymorphic associations (not useful at this juncture).
Currently what I have:
f.input :items, multiple: true, as: :select, collection: Section.top_level.all + NavigationItem.all
I'd also like to add that I have found stuff on polymorphic nested form stuff but again, not relevent to what I'm asking for.
Did you try to use select2 for AA ?
form do |f|
f.inputs do
f.input :sections, as: :select2_multiple, :collection => NavigationItem.find_by_sql('select * from navigation_items'}).pluck(:name, :id)
end
f.actions
end
You can use find_by_sql to search through all polymorphic model across main table. Of course you will want to modify the query to use correct models and section levels.

loopback relational database hasManyThrough pivot table

I seem to be stuck on a classic ORM issue and don't know really how to handle it, so at this point any help is welcome.
Is there a way to get the pivot table on a hasManyThrough query? Better yet, apply some filter or sort to it. A typical example
Table products
id,title
Table categories
id,title
table products_categories
productsId, categoriesId, orderBy, main
So, in the above scenario, say you want to get all categories of product X that are (main = true) or you want to sort the the product categories by orderBy.
What happens now is a first SELECT on products to get the product data, a second SELECT on products_categories to get the categoriesId and a final SELECT on categories to get the actual categories. Ideally, filters and sort should be applied to the 2nd SELECT like
SELECT `id`,`productsId`,`categoriesId`,`orderBy`,`main` FROM `products_categories` WHERE `productsId` IN (180) WHERE main = 1 ORDER BY `orderBy` DESC
Another typical example would be wanting to order the product images based on the order the user wants them to
so you would have a products_images table
id,image,productsID,orderBy
and you would want to
SELECT from products_images WHERE productsId In (180) ORDER BY orderBy ASC
Is that even possible?
EDIT : Here is the relationship needed for an intermediate table to get what I need based on my schema.
Products.hasMany(Images,
{
as: "Images",
"foreignKey": "productsId",
"through": ProductsImagesItems,
scope: function (inst, filter) {
return {active: 1};
}
});
Thing is the scope function is giving me access to the final result and not to the intermediate table.
I am not sure to fully understand your problem(s), but for sure you need to move away from the table concept and express your problem in terms of Models and Relations.
The way I see it, you have two models Product(properties: title) and Category (properties: main).
Then, you can have relations between the two, potentially
Product belongsTo Category
Category hasMany Product
This means a product will belong to a single category, while a category may contain many products. There are other relations available
Then, using the generated REST API, you can filter GET requests to get items in function of their properties (like main in your case), or use custom GET requests (automatically generated when you add relations) to get for instance all products belonging to a specific category.
Does this helps ?
Based on what you have here I'd probably recommend using the scope option when defining the relationship. The LoopBack docs show a very similar example of the "product - category" scenario:
Product.hasMany(Category, {
as: 'categories',
scope: function(instance, filter) {
return { type: instance.type };
}
});
In the example above, instance is a category that is being matched, and each product would have a new categories property that would contain the matching Category entities for that Product. Note that this does not follow your exact data scheme, so you may need to play around with it. Also, I think your API query would have to specify that you want the categories related data loaded (those are not included by default):
/api/Products/13?filter{"include":["categories"]}
I suggest you define a custom / remote method in Product.js that does the work for you.
Product.getCategories(_productId){
// if you are taking product title as param instead of _productId,
// you will first need to find product ID
// then execute a find query on products_categories with
// 1. where filter to get only main categoris and productId = _productId
// 2. include filter to include product and category objects
// 3. orderBy filter to sort items based on orderBy column
// now you will get an array of products_categories.
// Each item / object in the array will have nested objects of Product and Category.
}

Searching across multiple models using sunspot/solr

I have been able to implement a basic full text search successfully, however any queries involving models from many to many relations don't seem to work for me when i try to use scopes ("with statements"). I know the relevant rows are in the db as my sql statements do return the data. however the sunspot queries don't return any results…i'm sure its probably a newbie goof up on my end…any assistance would be greatly appreciated…so here we go….
My Models
class User
has_one :registration
searchable do
text :first_name
text :last_name
text :email
end
end
class Registration
belongs_to :user
has_many :registration_programs
has_many :programs, :through => :registration_programs
searchable do
integer :user_id
integer :registration_status_id
end
end
class RegistrationProgram
belongs_to :registration
belongs :program
searchable do
integer :registration_id
integer :program_id
end
end
My Query in the Controller
#search = Sunspot.search(User, Registration, RegistrationPrograms)do
# this works fine with the frame, lame, email fields "on its own"
fulltext params["instructor-search"]
any_of
all_of
with(:class => Registraion)
with(:registration_status_id, 3)
end
all_of
with(:class => RegistraionProgram)
with(:program_id, 1)
end
end
end
There are records in the database that have foo as f_name and 3 and 1 ids for their reg status and program fields. however i can't get Sunspot/websolr to get them….the only time i have had the above query to work is when i run all the three criteria "individually"….! Whenever I combine them i don't seem to get any rows returned.
Any help/suggestions would be greatly appreciated…….

CouchDB for Fixed Categories Queries

I have documents like this in my CouchDB:
{
"_id": "0cb35be3cc73d6859c303fa3200011d2",
"_rev": "1-f6e356bbf6ab09290aae11132af50d66",
"adresse": "Bohrgaß 10 /",
"plz": 56814,
"ort": "Faid /",
"kw": 2.32,
"traeger": "SOL"
...
}
There are predefined categories for certain attributes e.g. traeger: "SOL", "BIO", "WAS"; kw: <2, 2-5, 5-20, 20-100; plz: 56814, plz: 56815; ...
I have to be able to efficiently query the total number of docs for every category and
the total number of docs and the docs itself under certain conditions. E.g.
How many docs are in the category kw <2 (and all other kw categories) under the condition traeger = "SOL"
How many docs are in the category traeger = "SOL" (and all other traeger categories) under the conditions plz=56814 AND kw < 2
The user can select which catagories he likes to combine. The categories are fix. There also will be more attributes and catagories.
How would map/ reduce functions for this look like?
Marcel
Since you are going to count documents, your reduce function is simply the built-in count. Your map function needs to emit the appropriate keys your users are going to search for. Finally, when the view is queried, the appropriate group level has to be picked.
Example: You can create a view with a composite key ["traeger", "kw"]. If you query that view with group_level = 2, you get the number of documents for each combination of traeger and kw.
If you only care about the traeger "SOL", you can restrict the output with the start_key and end_key parameters.
If you want to know the number of documents in each "traeger" category no matter their "kw", you can query that view with group_level 1.
For your second example, you can create a view with the key ["plz","kw","traeger"] and query it using start_key and end_key to restrict the results to plz=56814 AND kw < 2 and set group_level to 3.
Querying options for views are listed here:
http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options

Resources